summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorCédric Bosdonnat <cedric.bosdonnat@free.fr>2013-04-10 16:56:44 +0200
committerCédric Bosdonnat <cedric.bosdonnat@free.fr>2013-07-31 12:57:50 +0200
commit82e888c6f6d5f99ebb84758723409d2cc61961d6 (patch)
tree8b467ed5f5c60f91b2f954ca75818df999e4464e /common
parentefb5feb956405d9311db11d61cb3557a4abfa435 (diff)
moved gvfsuriutils.{ch} back to common to use them in cmis backend later
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am7
-rw-r--r--common/gvfsuriutils.c295
-rw-r--r--common/gvfsuriutils.h49
-rw-r--r--common/test-uri-utils.c60
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;
+}
+