From d200208d2b8bad7babdd56f4ec6fcae1589e142b Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 13 Feb 2013 20:42:58 +0000 Subject: [PATCH] g_dbus_address_escape_value: add This is a GLib reimplementation of dbus_address_escape_value(). It's useful if you want to construct a D-Bus address from pieces: for instance, if you have a listening Unix socket whose path is known, and you want to connect a D-Bus peer to it. Bug: https://bugzilla.gnome.org/show_bug.cgi?id=693673 Reviewed-by: Colin Walters [amended to add Since: 2.36 as per review] Signed-off-by: Simon McVittie --- gio/gdbusaddress.c | 47 +++++++++++++++++++++++++++++++++++++ gio/gdbusaddress.h | 3 +++ gio/tests/gdbus-addresses.c | 24 +++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index 8c1d31c76..cc9703c96 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -1586,3 +1586,50 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, return ret; } + +/** + * g_dbus_address_escape_value: + * @string: an unescaped string to be included in a D-Bus address + * as the value in a key-value pair + * + * Escape @string so it can appear in a D-Bus address as the value + * part of a key-value pair. + * + * For instance, if @string is /run/bus-for-:0, + * this function would return /run/bus-for-%3A0, + * which could be used in a D-Bus address like + * unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0. + * + * Returns: (transfer full): a copy of @string with all + * non-optionally-escaped bytes escaped + * + * Since: 2.36 + */ +gchar * +g_dbus_address_escape_value (const gchar *string) +{ + GString *s; + gsize i; + + g_return_val_if_fail (string != NULL, NULL); + + /* There will often not be anything needing escaping at all. */ + s = g_string_sized_new (strlen (string)); + + /* D-Bus address escaping is mostly the same as URI escaping... */ + g_string_append_uri_escaped (s, string, "\\/", FALSE); + + /* ... but '~' is an unreserved character in URIs, but a + * non-optionally-escaped character in D-Bus addresses. */ + for (i = 0; i < s->len; i++) + { + if (G_UNLIKELY (s->str[i] == '~')) + { + s->str[i] = '%'; + g_string_insert (s, i + 1, "7E"); + i += 2; + } + } + + return g_string_free (s, FALSE); +} diff --git a/gio/gdbusaddress.h b/gio/gdbusaddress.h index 55896b8f2..08773aa4c 100644 --- a/gio/gdbusaddress.h +++ b/gio/gdbusaddress.h @@ -31,6 +31,9 @@ G_BEGIN_DECLS +GLIB_AVAILABLE_IN_2_36 +gchar *g_dbus_address_escape_value (const gchar *string); + GLIB_AVAILABLE_IN_ALL gboolean g_dbus_is_address (const gchar *string); GLIB_AVAILABLE_IN_ALL diff --git a/gio/tests/gdbus-addresses.c b/gio/tests/gdbus-addresses.c index 72388c5aa..c5a237d0a 100644 --- a/gio/tests/gdbus-addresses.c +++ b/gio/tests/gdbus-addresses.c @@ -102,6 +102,29 @@ test_mixed_address (void) g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=42;tcp:family=bla", NULL)); } +static const struct { const char *before; const char *after; } escaping[] = { + { "foo", "foo" }, + { "/.\\-_", "/.\\-_" }, + { "<=>", "%3C%3D%3E" }, + { "/foo~1", "/foo%7E1" }, + { "\xe2\x98\xad\xff", "%E2%98%AD%FF" }, + { NULL, NULL } +}; + +static void +test_escape_address (void) +{ + gsize i; + + for (i = 0; escaping[i].before != NULL; i++) + { + gchar *s = g_dbus_address_escape_value (escaping[i].before); + + g_assert_cmpstr (s, ==, escaping[i].after); + g_free (s); + } +} + int main (int argc, char *argv[]) @@ -116,6 +139,7 @@ main (int argc, g_test_add_func ("/gdbus/tcp-address", test_tcp_address); g_test_add_func ("/gdbus/autolaunch-address", test_autolaunch_address); g_test_add_func ("/gdbus/mixed-address", test_mixed_address); + g_test_add_func ("/gdbus/escape-address", test_escape_address); return g_test_run(); }