[gupnp/wip/phako/libsoup3: 19/19] wip: More libsoup3 fixes




commit 2b28a0ba62547fbe5ed63de6a3cf8614c87c10e8
Author: Jens Georg <mail jensge org>
Date:   Sat Aug 7 09:46:54 2021 +0200

    wip: More libsoup3 fixes

 .gitlab-ci.yml                    |   3 +-
 build-aux/org.gnome.GUPnP.json    |  59 ++++++++++++++
 libgupnp/gupnp-context.c          |   4 +-
 libgupnp/gupnp-resource-factory.c |   3 +-
 libgupnp/gupnp-root-device.c      |   5 +-
 libgupnp/gupnp-service-info.c     |  18 ++---
 libgupnp/gupnp-service.c          |  51 ++++++-------
 libgupnp/meson.build              |   2 +-
 tests/meson.build                 |   5 +-
 tests/test-bugs.c                 |   2 -
 tests/test-service.c              | 156 ++++++++++++++++++++++++++++++++++++++
 vala/gupnp-1.2.deps               |   2 +-
 vala/meson.build                  |   2 +-
 13 files changed, 257 insertions(+), 55 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6f36e91..0670d37 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,8 +4,7 @@ flatpak:
   image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
   stage: build
   script:
-    - curl https://gitlab.gnome.org/GNOME/rygel/-/raw/master/build-aux/org.gnome.Rygel.json | sed 
's/40/master/' >org.gnome.Rygel.json
-    - flatpak-builder build-dir org.gnome.Rygel.json --stop-at=gupnp --user --disable-rofiles-fuse
+    - flatpak-builder build-dir build-aux/org.gnome.GUPnP.json --stop-at=gupnp --user --disable-rofiles-fuse
     - flatpak build build-dir meson _build
     - flatpak build build-dir ninja -C _build
     - flatpak build build-dir meson test -C _build --gdb
diff --git a/build-aux/org.gnome.GUPnP.json b/build-aux/org.gnome.GUPnP.json
new file mode 100644
index 0000000..b7967d3
--- /dev/null
+++ b/build-aux/org.gnome.GUPnP.json
@@ -0,0 +1,59 @@
+{
+    "app-id" : "org.gnome.GUPnP",
+    "runtime" : "org.gnome.Platform",
+    "runtime-version" : "master",
+    "sdk" : "org.gnome.Sdk",
+    "command" : "light-server",
+    "finish-args" : [
+        "--share=network",
+        "--share=ipc",
+        "--talk-name=org.gtk.vfs",
+        "--talk-name=org.gtk.vfs.*",
+        "--filesystem=xdg-pictures",
+        "--filesystem=xdg-videos",
+        "--filesystem=xdg-music",
+        "--own-name=org.gnome.Rygel1"
+    ],
+    "build-options" : {
+        "cflags" : "-O2 -g",
+        "cxxflags" : "-O2 -g",
+        "env" : {
+            "V" : "1"
+        }
+    },
+    "cleanup" : [
+        "/include",
+        "/lib/pkgconfig",
+        "/man",
+        "/share/doc",
+        "/share/gtk-doc",
+        "/share/man",
+        "/share/pkgconfig",
+        "*.la",
+        "*.a"
+    ],
+    "modules" : [
+        {
+            "name" : "gssdp",
+            "buildsystem" : "meson",
+            "sources" : [
+                {
+                    "type" : "git",
+                    "url" : "https://gitlab.gnome.org/GNOME/gssdp.git/";,
+                    "branch" : "wip/libsoup3"
+                }
+            ]
+        },
+        {
+            "name" : "gupnp",
+            "buildsystem" : "meson",
+            "sources" : [
+                {
+                    "type" : "git",
+                    "url" : "https://gitlab.gnome.org/GNOME/gupnp.git/";,
+                    "branch" : "wip/phako/libsoup3"
+                }
+            ]
+        }
+    ]
+}
diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c
index 6a0caa4..04b521d 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -628,6 +628,7 @@ make_server_uri (GUPnPContext *context)
         {
                 GUri *uri = g_uri_ref (uris->data);
                 g_slist_free_full (uris, (GDestroyNotify) g_uri_unref);
+
                 return uri;
         }
         return NULL;
@@ -946,6 +947,7 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
         HostPathData *host_path_data;
         const char *user_agent;
         const char *host;
+        GBytes *buffer = NULL;
 
         orig_locales = NULL;
         locales      = NULL;
@@ -1092,7 +1094,7 @@ host_path_handler (G_GNUC_UNUSED SoupServer *server,
         // Creating the buffer here regardless of whether we use it.
         // It will take ownership of the mapped file and we can unref it on exit
         // This will prevent leaking the mapped file in other cases
-        GBytes *buffer = g_bytes_new_with_free_func (
+        buffer = g_bytes_new_with_free_func (
                 g_mapped_file_get_contents (mapped_file),
                 g_mapped_file_get_length (mapped_file),
                 (GDestroyNotify) g_mapped_file_unref,
diff --git a/libgupnp/gupnp-resource-factory.c b/libgupnp/gupnp-resource-factory.c
index 32dca4b..6d2b798 100644
--- a/libgupnp/gupnp-resource-factory.c
+++ b/libgupnp/gupnp-resource-factory.c
@@ -36,8 +36,7 @@ typedef struct _GUPnPResourceFactoryPrivate GUPnPResourceFactoryPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GUPnPResourceFactory,
                             gupnp_resource_factory,
-                            G_TYPE_OBJECT);
-
+                            G_TYPE_OBJECT)
 
 static void
 gupnp_resource_factory_init (GUPnPResourceFactory *factory)
diff --git a/libgupnp/gupnp-root-device.c b/libgupnp/gupnp-root-device.c
index 6643dc9..3c337fc 100644
--- a/libgupnp/gupnp-root-device.c
+++ b/libgupnp/gupnp-root-device.c
@@ -92,10 +92,7 @@ gupnp_root_device_dispose (GObject *object)
         device = GUPNP_ROOT_DEVICE (object);
         priv = gupnp_root_device_get_instance_private (device);
 
-        if (priv->group) {
-                g_object_unref (priv->group);
-                priv->group = NULL;
-        }
+        g_clear_object (&priv->group);
 
         /* Call super */
         object_class = G_OBJECT_CLASS (gupnp_root_device_parent_class);
diff --git a/libgupnp/gupnp-service-info.c b/libgupnp/gupnp-service-info.c
index 2a66141..ccc0f23 100644
--- a/libgupnp/gupnp-service-info.c
+++ b/libgupnp/gupnp-service-info.c
@@ -81,8 +81,8 @@ typedef struct {
 static void
 get_scpd_url_data_free (GetSCPDURLData *data)
 {
-        if (data->cancellable)
-                g_object_unref (data->cancellable);
+        g_clear_object (&data->cancellable);
+        g_clear_object (&data->message);
 
         g_slice_free (GetSCPDURLData, data);
 }
@@ -209,10 +209,7 @@ gupnp_service_info_dispose (GObject *object)
                 priv->context = NULL;
         }
 
-        if (priv->doc) {
-                g_object_unref (priv->doc);
-                priv->doc = NULL;
-        }
+        g_clear_object (&priv->doc);
 
         G_OBJECT_CLASS (gupnp_service_info_parent_class)->dispose (object);
 }
@@ -625,13 +622,10 @@ got_scpd_url (GObject *source, GAsyncResult *res, GetSCPDURLData *data)
         priv = gupnp_service_info_get_instance_private (data->info);
         priv->pending_gets = g_list_remove (priv->pending_gets, data);
 
-        data->callback (data->info,
-                        introspection,
-                        error,
-                        data->user_data);
+        data->callback (data->info, introspection, error, data->user_data);
 
-        if (error)
-                g_error_free (error);
+        g_clear_error (&error);
+        g_clear_pointer (&body, g_bytes_unref);
 
         get_scpd_url_data_free (data);
 }
diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c
index 14f34ce..d80bb3c 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -108,8 +108,15 @@ typedef struct {
                                            subscription */
         gboolean      initial_state_sent;
         gboolean      to_delete;
+        GCancellable *cancellable;
 } SubscriptionData;
 
+typedef struct {
+        SubscriptionData *data;
+        SoupMessage *msg;
+        GBytes *property_set;
+} NotifySubscriberData;
+
 static gboolean
 subscription_data_can_delete (SubscriptionData *data) {
     return data->initial_state_sent && data->to_delete;
@@ -161,22 +168,17 @@ gupnp_service_get_session (GUPnPService *service)
 static void
 subscription_data_free (SubscriptionData *data)
 {
-        // SoupSession *session;
+        g_cancellable_cancel (data->cancellable);
+        g_clear_object (&data->cancellable);
 
         // session = gupnp_service_get_session (data->service);
 
         /* Cancel pending messages */
         while (data->pending_messages) {
-                /*
-                SoupMessage *msg;
-
-                msg = data->pending_messages->data;
-
-                 * FIXME: cancel elsewhere
-                soup_session_cancel_message (session,
-                                             msg,
-                                             SOUP_STATUS_CANCELLED);
-                 */
+                NotifySubscriberData *d = data->pending_messages->data;
+                g_object_unref (d->msg);
+                g_bytes_unref (d->property_set);
+                g_free (d);
 
                 data->pending_messages =
                         g_list_delete_link (data->pending_messages,
@@ -1265,6 +1267,7 @@ subscribe (GUPnPService *service, SoupServerMessage *msg, const char *callback)
                                         (GUPNP_SERVICE_INFO (service));
 
         data = g_slice_new0 (SubscriptionData);
+        data->cancellable = g_cancellable_new ();
 
         /* Parse callback list */
         start = (char *) callback;
@@ -1334,6 +1337,9 @@ subscribe (GUPnPService *service, SoupServerMessage *msg, const char *callback)
         /* Respond */
         subscription_response (service, msg, data->sid, SUBSCRIPTION_TIMEOUT);
 
+        // FIXME: Should we only send this if we priv->inspection is not NULL?
+        // There might not be any useful data in the notification if there is no
+        // introspection yet
         send_initial_state (data);
 }
 
@@ -1892,7 +1898,7 @@ gupnp_service_class_init (GUPnPServiceClass *klass)
         /**
          * GUPnPService::notify-failed:
          * @service: The #GUPnPService that received the signal
-         * @callback_url: (type GList)(element-type SoupURI):A #GList of callback URLs
+         * @callback_url: (type GList)(element-type GUri):A #GList of callback URLs
          * @reason: (type GError): A pointer to a #GError describing why the notify failed
          *
          * Emitted whenever notification of a client fails.
@@ -1979,11 +1985,6 @@ gupnp_service_notify_valist (GUPnPService *service,
         }
 }
 
-typedef struct {
-        SubscriptionData *data;
-        SoupMessage *msg;
-        GBytes *property_set;
-} NotifySubscriberData;
 
 /* Received notify response. */
 static void
@@ -1992,6 +1993,7 @@ notify_got_response (GObject *source, GAsyncResult *res, gpointer user_data)
 
         GBytes *body;
         GError *error = NULL;
+        NotifySubscriberData *data = user_data;
 
         body = soup_session_send_and_read_finish (SOUP_SESSION (source),
                                                   res,
@@ -2000,20 +2002,19 @@ notify_got_response (GObject *source, GAsyncResult *res, gpointer user_data)
         /* Cancelled? */
         if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
                 g_clear_error (&error);
-
+                // Do nothing else. The data was freed after the message was
+                // cancelled
                 return;
         }
 
         // We don't need the body
         g_clear_pointer (&body, g_bytes_unref);
 
-        NotifySubscriberData *data = user_data;
-
         SoupStatus status = soup_message_get_status (data->msg);
 
         /* Remove from pending messages list */
         data->data->pending_messages =
-                g_list_remove (data->data->pending_messages, data->msg);
+                g_list_remove (data->data->pending_messages, data);
 
         if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
                 data->data->initial_state_sent = TRUE;
@@ -2035,7 +2036,6 @@ notify_got_response (GObject *source, GAsyncResult *res, gpointer user_data)
                         notify_subscriber (NULL,
                                            data->data,
                                            g_bytes_ref (data->property_set));
-                        g_bytes_unref (data->property_set);
                 } else {
                         /* Emit 'notify-failed' signal */
                         GError *inner_error;
@@ -2058,7 +2058,6 @@ notify_got_response (GObject *source, GAsyncResult *res, gpointer user_data)
                                 g_list_first (data->data->callbacks);
                 }
         }
-
         g_clear_error (&error);
         g_bytes_unref (data->property_set);
         g_object_unref (data->msg);
@@ -2091,9 +2090,7 @@ notify_subscriber (G_GNUC_UNUSED gpointer key,
                 soup_message_get_request_headers (data->msg);
 
         soup_message_headers_append (request_headers, "NT", "upnp:event");
-
         soup_message_headers_append (request_headers, "NTS", "upnp:propchange");
-
         soup_message_headers_append (request_headers, "SID", data->data->sid);
 
         tmp = g_strdup_printf ("%d", data->data->seq);
@@ -2113,7 +2110,7 @@ notify_subscriber (G_GNUC_UNUSED gpointer key,
 
         /* Queue */
         data->data->pending_messages =
-                g_list_prepend (data->data->pending_messages, data->msg);
+                g_list_prepend (data->data->pending_messages, data);
         soup_message_headers_append (request_headers, "Connection", "close");
 
         session = gupnp_service_get_session (data->data->service);
@@ -2122,7 +2119,7 @@ notify_subscriber (G_GNUC_UNUSED gpointer key,
                 session,
                 data->msg,
                 G_PRIORITY_DEFAULT,
-                NULL,
+                data->data->cancellable,
                 (GAsyncReadyCallback) notify_got_response,
                 data);
 }
diff --git a/libgupnp/meson.build b/libgupnp/meson.build
index cb8a102..1484ce0 100644
--- a/libgupnp/meson.build
+++ b/libgupnp/meson.build
@@ -136,7 +136,7 @@ pkg.generate(
 )
 
 if get_option('introspection')
-    gir_includes = ['GObject-2.0', 'Gio-2.0', 'Soup-2.4', 'libxml2-2.0']
+    gir_includes = ['GObject-2.0', 'Gio-2.0', 'Soup-3.0', 'libxml2-2.0']
     if gssdp_dep.type_name() == 'internal'
         gir_includes += subproject('gssdp-1.2').get_variable('gir').get(0)
     else
diff --git a/tests/meson.build b/tests/meson.build
index 33637d7..a6f0b4b 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,11 +1,12 @@
-foreach program : ['context', 'bugs']
+foreach program : ['context', 'bugs', 'service']
     test(
         program,
         executable(
             'test-' + program,
             'test-@0@.c'.format (program),
             dependencies : gupnp,
-            c_args : '-DDATA_PATH="@0@/data"'.format(meson.current_source_dir())
+            c_args : '-DDATA_PATH="@0@/data"'.format(meson.current_source_dir()),
+            include_directories : config_h_inc,
         ),
         is_parallel : false
     )
diff --git a/tests/test-bugs.c b/tests/test-bugs.c
index b99ffd2..0b41011 100644
--- a/tests/test-bugs.c
+++ b/tests/test-bugs.c
@@ -6,9 +6,7 @@
  * SPDX-License-Identifier: LGPL-2.1-or-later
  */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
 
 #include <libgupnp/gupnp.h>
 #include <libgupnp/gupnp-service-private.h>
diff --git a/tests/test-service.c b/tests/test-service.c
new file mode 100644
index 0000000..c69910c
--- /dev/null
+++ b/tests/test-service.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include <config.h>
+
+#include <libgupnp/gupnp-xml-doc.h>
+
+#include <libgupnp/gupnp-context-private.h>
+#include <libgupnp/gupnp-service-private.h>
+#include <libgupnp/gupnp.h>
+
+static GUPnPContext *
+create_context (guint16 port, GError **error)
+{
+        return GUPNP_CONTEXT (g_initable_new (GUPNP_TYPE_CONTEXT,
+                                              NULL,
+                                              error,
+                                              "host-ip",
+                                              "127.0.0.1",
+                                              "msearch-port",
+                                              port,
+                                              NULL));
+}
+
+typedef struct {
+        GMainLoop *loop;
+        SoupServerMessage *message;
+} TestServiceNotificationCancelledData;
+
+void
+on_notify (SoupServer *server,
+           SoupServerMessage *msg,
+           const char *path,
+           GHashTable *query,
+           gpointer user_data)
+{
+        TestServiceNotificationCancelledData *data = user_data;
+
+        // Pause message, quit mainlopp
+        soup_server_pause_message (server, msg);
+        data->message = msg;
+        g_main_loop_quit (data->loop);
+}
+
+void
+on_subscribe (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+        GError *error = NULL;
+
+        GBytes *data = soup_session_send_and_read_finish (SOUP_SESSION (source),
+                                                          res,
+                                                          &error);
+
+        g_assert_no_error (error);
+        g_clear_pointer (&data, g_bytes_unref);
+}
+
+static void
+on_finished (SoupServerMessage *msg, TestServiceNotificationCancelledData *data)
+{
+        g_assert_cmpint (soup_server_message_get_status (msg),
+                         ==,
+                         SOUP_STATUS_INTERNAL_SERVER_ERROR);
+        g_main_loop_quit (data->loop);
+}
+
+static void
+test_service_notification_cancelled ()
+{
+        GUPnPContext *context = NULL;
+        GError *error = NULL;
+        GUPnPRootDevice *rd;
+        GUPnPServiceInfo *info = NULL;
+
+        TestServiceNotificationCancelledData data = { NULL, NULL };
+
+        data.loop = g_main_loop_new (NULL, FALSE);
+
+        context = create_context (0, &error);
+        g_assert_no_error (error);
+        g_assert (context != NULL);
+
+        rd = gupnp_root_device_new (context,
+                                    "TestDevice.xml",
+                                    DATA_PATH,
+                                    &error);
+        g_assert_no_error (error);
+        g_assert (rd != NULL);
+        gupnp_root_device_set_available (rd, TRUE);
+
+        SoupServer *server = soup_server_new (NULL, NULL);
+        soup_server_add_handler (server, "/Notify", on_notify, &data, NULL);
+        soup_server_listen_local (server,
+                                  0,
+                                  SOUP_SERVER_LISTEN_IPV4_ONLY,
+                                  &error);
+        g_assert_no_error (error);
+
+        // Generate SUBSCRIBE message
+        info = gupnp_device_info_get_service (
+                GUPNP_DEVICE_INFO (rd),
+                "urn:test-gupnp-org:service:TestService:1");
+        char *url = gupnp_service_info_get_event_subscription_url (info);
+        SoupMessage *msg = soup_message_new ("SUBSCRIBE", url);
+        g_free (url);
+
+        GSList *uris = soup_server_get_uris (server);
+        GUri *subscription =
+                soup_uri_copy (uris->data, SOUP_URI_PATH, "/Notify", NULL);
+        char *uri_string = g_uri_to_string (subscription);
+        char *callback = g_strdup_printf ("<%s>", uri_string);
+        g_free (uri_string);
+        g_slist_free_full (uris, (GDestroyNotify) g_uri_unref);
+        g_uri_unref (subscription);
+
+        SoupMessageHeaders *h = soup_message_get_request_headers (msg);
+        soup_message_headers_append (h, "Callback", callback);
+        g_free (callback);
+
+        soup_message_headers_append (h, "NT", "upnp:event");
+        SoupSession *session = soup_session_new ();
+        // FIXME: Add timeout header
+        soup_session_send_and_read_async (session,
+                                          msg,
+                                          G_PRIORITY_DEFAULT,
+                                          NULL,
+                                          on_subscribe,
+                                          &data);
+
+        g_main_loop_run (data.loop);
+        g_signal_connect (data.message,
+                          "finished",
+                          G_CALLBACK (on_finished),
+                          &data);
+
+        g_clear_object (&info);
+
+        soup_server_unpause_message (server, data.message);
+
+        g_main_loop_run (data.loop);
+        g_clear_object (&rd);
+        g_clear_object (&msg);
+        g_clear_object (&session);
+        g_clear_object (&server);
+        g_clear_object (&context);
+        g_main_loop_unref (data.loop);
+}
+int
+main (int argc, char *argv[])
+{
+        g_test_init (&argc, &argv, NULL);
+
+        g_test_add_func ("/service/notify/cancel",
+                         test_service_notification_cancelled);
+
+        return g_test_run ();
+}
diff --git a/vala/gupnp-1.2.deps b/vala/gupnp-1.2.deps
index 48dcf61..1085e17 100644
--- a/vala/gupnp-1.2.deps
+++ b/vala/gupnp-1.2.deps
@@ -1,3 +1,3 @@
 gssdp-1.2
-libsoup-2.4
+libsoup-3.0
 libxml-2.0
diff --git a/vala/meson.build b/vala/meson.build
index aacaa71..3ab40fc 100644
--- a/vala/meson.build
+++ b/vala/meson.build
@@ -8,7 +8,7 @@ endif
 
 gnome.generate_vapi('gupnp-1.2',
                     sources : [gir.get(0), 'gupnp-1.2-custom.vala'],
-                    packages : [gssdp_vala_package, 'gio-2.0', 'libsoup-2.4', 'libxml-2.0'],
+                    packages : [gssdp_vala_package, 'gio-2.0', 'libsoup-3.0', 'libxml-2.0'],
                     gir_dirs : gssdp_gir_dirs,
                     install : true
 )


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]