gdbusconnection: Support matching object paths with arg0 matching

GDBus has always supported matching strings with arg0 matching
(`G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH`). In D-Bus 1.5, support was added
to the spec for also matching object paths. This got forgotten about and
was never added to GDBus, meaning that
`G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH` won’t match against a signal arg0
of type `o`.

Fix that, and add a unit test.

To do so, we need to add a new `g_dbus_message_get_arg0_path()` API to
complement the existing `g_dbus_message_get_arg0()` API. The approach of
letting `g_dbus_message_get_arg0()` return an object-path *or* a string
would not work, as it’s also called in the implementation of
`G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE`, which must only match
string-typed arg0 values and not object-path-typed ones.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #3183
This commit is contained in:
Philip Withnall 2023-11-22 12:40:07 +00:00
parent 10e9a917be
commit 96c317418a
4 changed files with 61 additions and 21 deletions

View File

@ -3867,16 +3867,22 @@ schedule_callbacks (GDBusConnection *connection,
const gchar *member;
const gchar *path;
const gchar *arg0;
const gchar *arg0_path;
interface = NULL;
member = NULL;
path = NULL;
arg0 = NULL;
arg0_path = NULL;
interface = g_dbus_message_get_interface (message);
member = g_dbus_message_get_member (message);
path = g_dbus_message_get_path (message);
arg0 = g_dbus_message_get_arg0 (message);
arg0_path = g_dbus_message_get_arg0_path (message);
/* These two are mutually exclusive through the type system. */
g_assert (arg0 == NULL || arg0_path == NULL);
#if 0
g_print ("In schedule_callbacks:\n"
@ -3910,17 +3916,15 @@ schedule_callbacks (GDBusConnection *connection,
if (signal_data->arg0 != NULL)
{
if (arg0 == NULL)
continue;
if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE)
{
if (!namespace_rule_matches (signal_data->arg0, arg0))
if (arg0 == NULL || !namespace_rule_matches (signal_data->arg0, arg0))
continue;
}
else if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH)
{
if (!path_rule_matches (signal_data->arg0, arg0))
if ((arg0 == NULL || !path_rule_matches (signal_data->arg0, arg0)) &&
(arg0_path == NULL || !path_rule_matches (signal_data->arg0, arg0_path)))
continue;
}
else if (!g_str_equal (signal_data->arg0, arg0))

View File

@ -3400,6 +3400,9 @@ g_dbus_message_set_signature (GDBusMessage *message,
*
* Convenience to get the first item in the body of @message.
*
* See [method@Gio.DBusMessage.get_arg0_path] for returning object-path-typed
* arg0 values.
*
* Returns: (nullable): The string item or %NULL if the first item in the body of
* @message is not a string.
*
@ -3417,6 +3420,31 @@ g_dbus_message_get_arg0 (GDBusMessage *message)
return NULL;
}
/**
* g_dbus_message_get_arg0_path:
* @message: A `GDBusMessage`.
*
* Convenience to get the first item in the body of @message.
*
* See [method@Gio.DBusMessage.get_arg0] for returning string-typed arg0 values.
*
* Returns: (nullable): The object path item or `NULL` if the first item in the
* body of @message is not an object path.
*
* Since: 2.80
*/
const gchar *
g_dbus_message_get_arg0_path (GDBusMessage *message)
{
g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
if (message->arg0_cache != NULL &&
g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_OBJECT_PATH))
return g_variant_get_string (message->arg0_cache, NULL);
return NULL;
}
/* ---------------------------------------------------------------------------------------------------- */
/**

View File

@ -176,7 +176,8 @@ void g_dbus_message_set_num_unix_fds (GDBusMessage
GIO_AVAILABLE_IN_ALL
const gchar *g_dbus_message_get_arg0 (GDBusMessage *message);
GIO_AVAILABLE_IN_2_80
const gchar *g_dbus_message_get_arg0_path (GDBusMessage *message);
GIO_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_from_blob (guchar *blob,

View File

@ -742,6 +742,7 @@ test_match_rule (GDBusConnection *connection,
GDBusSignalFlags flags,
gchar *arg0_rule,
gchar *arg0,
const gchar *signal_type,
gboolean should_match)
{
guint subscription_ids[2];
@ -766,7 +767,7 @@ test_match_rule (GDBusConnection *connection,
g_dbus_connection_emit_signal (connection,
NULL, "/", "org.gtk.ExampleInterface",
"Foo", g_variant_new ("(s)", arg0),
"Foo", g_variant_new (signal_type, arg0),
&error);
g_assert_no_error (error);
@ -793,22 +794,28 @@ test_connection_signal_match_rules (void)
session_bus_up ();
con = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "foo", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "bar", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "foo", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "bar", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk.Example", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk+", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk.Example", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk+", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/", "(s)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(s)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(o)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(o)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(o)", TRUE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(o)", FALSE);
test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(o)", FALSE);
g_object_unref (con);
session_bus_down ();