diff options
author | Cédric Bosdonnat <cedric.bosdonnat@free.fr> | 2013-04-10 16:56:44 +0200 |
---|---|---|
committer | Cédric Bosdonnat <cedric.bosdonnat@free.fr> | 2013-07-31 12:57:50 +0200 |
commit | 82e888c6f6d5f99ebb84758723409d2cc61961d6 (patch) | |
tree | 8b467ed5f5c60f91b2f954ca75818df999e4464e /common | |
parent | efb5feb956405d9311db11d61cb3557a4abfa435 (diff) |
moved gvfsuriutils.{ch} back to common to use them in cmis backend later
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile.am | 7 | ||||
-rw-r--r-- | common/gvfsuriutils.c | 295 | ||||
-rw-r--r-- | common/gvfsuriutils.h | 49 | ||||
-rw-r--r-- | common/test-uri-utils.c | 60 |
4 files changed, 411 insertions, 0 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 07ac8f42..2d0e1a9c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -27,6 +27,7 @@ libgvfscommon_la_SOURCES = \ gvfsdaemonprotocol.c gvfsdaemonprotocol.h \ gvfsicon.h gvfsicon.c \ gvfsfileinfo.c gvfsfileinfo.h \ + gvfsuriutils.c gvfsuriutils.h \ $(dbus_built_sources) \ $(NULL) @@ -67,6 +68,12 @@ libgvfscommon_dnssd_la_LIBADD = \ $(GLIB_LIBS) endif +noinst_PROGRAMS = test-uri-utils + +test_uri_utils_SOURCES = test-uri-utils.c gvfsuriutils.c gvfsuriutils.h +test_uri_utils_LDADD = $(GLIB_LIBS) +test_uri_utils_CFLAGS = $(INCLUDES) + EXTRA_DIST = org.gtk.vfs.xml diff --git a/common/gvfsuriutils.c b/common/gvfsuriutils.c new file mode 100644 index 00000000..58a71e19 --- /dev/null +++ b/common/gvfsuriutils.c @@ -0,0 +1,295 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Alexander Larsson <alexl@redhat.com> + */ + +#include <config.h> +#include "gvfsuriutils.h" +#include <string.h> +#include <stdlib.h> + +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) + { + userinfo_start = authority_start; + decoded->userinfo = g_uri_unescape_segment (userinfo_start, userinfo_end, NULL); + if (decoded->userinfo == NULL) + { + g_vfs_decoded_uri_free (decoded); + return NULL; + } + host_start = userinfo_end + 1; + } + 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; + } + + 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, '@'); + } + + 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); +} diff --git a/common/gvfsuriutils.h b/common/gvfsuriutils.h new file mode 100644 index 00000000..3d585931 --- /dev/null +++ b/common/gvfsuriutils.h @@ -0,0 +1,49 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Alexander Larsson <alexl@redhat.com> + */ + +#ifndef __G_VFS_URI_UTILS_H__ +#define __G_VFS_URI_UTILS_H__ + +#include <glib.h> + +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); + + +G_END_DECLS + +#endif /* __G_VFS_URI_UTILS_H__ */ diff --git a/common/test-uri-utils.c b/common/test-uri-utils.c new file mode 100644 index 00000000..4d21f165 --- /dev/null +++ b/common/test-uri-utils.c @@ -0,0 +1,60 @@ + +#include <string.h> + +#include "gvfsuriutils.h" + + +typedef struct { + const char *uri; + const char *expected_host; + guint 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 }, + { "obex://[00:FF:FF:FF:FF:FF]/MMC/foo.jpg", "[00:FF:FF:FF:FF:FF]", -1 }, + { "obex://[00:FF:FF:FF:FF:FF]/C:", "[00:FF:FF:FF:FF:FF]", -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 }, +}; + +int main (int argc, char **argv) +{ + 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); + } + + return 0; +} + |