[gnome-software/wip/mcrha/soup3] Misc: Port to libsoup3



commit 9a9cda09325b44d83e2ff5450b642c7e52c12bb6
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 12 12:10:35 2021 +0100

    Misc: Port to libsoup3
    
    This is a conditional port, allows to build either with libsoup3
    or with libsoup2. Which had been used is indicated in the gnome-software.pc
    variable `soupapiversion`.

 lib/gs-app.c                        |   8 +-
 lib/gs-external-appstream-utils.c   |  29 +++++-
 lib/gs-odrs-provider.c              | 174 +++++++++++++++++++++++++++++-------
 lib/gs-plugin-loader.c              |   6 +-
 lib/gs-plugin.c                     | 139 +++++++++++++++++++++++++---
 lib/gs-remote-icon.c                |  14 ++-
 lib/gs-utils.c                      |  20 ++---
 lib/meson.build                     |   1 +
 meson.build                         |  19 +++-
 meson_options.txt                   |   1 +
 plugins/core/gs-plugin-os-release.c |   6 +-
 plugins/fwupd/gs-plugin-fwupd.c     |   4 +-
 src/gs-application.c                |   1 -
 src/gs-details-page.c               |   5 --
 src/gs-page.c                       |   4 +-
 src/gs-repo-row.c                   |   8 +-
 src/gs-screenshot-carousel.c        |   2 +-
 src/gs-screenshot-image.c           | 106 +++++++++++++++++++---
 18 files changed, 445 insertions(+), 102 deletions(-)
---
diff --git a/lib/gs-app.c b/lib/gs-app.c
index 512aa2cf9..fd09e358d 100644
--- a/lib/gs-app.c
+++ b/lib/gs-app.c
@@ -2957,7 +2957,7 @@ gs_app_set_origin_hostname (GsApp *app, const gchar *origin_hostname)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
        g_autoptr(GMutexLocker) locker = NULL;
-       g_autoptr(SoupURI) uri = NULL;
+       g_autoptr(GUri) uri = NULL;
        guint i;
        const gchar *prefixes[] = { "download.", "mirrors.", NULL };
 
@@ -2970,10 +2970,10 @@ gs_app_set_origin_hostname (GsApp *app, const gchar *origin_hostname)
                return;
        g_free (priv->origin_hostname);
 
-       /* use libsoup to convert a URL */
-       uri = soup_uri_new (origin_hostname);
+       /* convert a URL */
+       uri = g_uri_parse (origin_hostname, SOUP_HTTP_URI_FLAGS, NULL);
        if (uri != NULL)
-               origin_hostname = soup_uri_get_host (uri);
+               origin_hostname = g_uri_get_host (uri);
 
        /* remove some common prefixes */
        for (i = 0; prefixes[i] != NULL; i++) {
diff --git a/lib/gs-external-appstream-utils.c b/lib/gs-external-appstream-utils.c
index 73c567443..e227d77b5 100644
--- a/lib/gs-external-appstream-utils.c
+++ b/lib/gs-external-appstream-utils.c
@@ -95,6 +95,8 @@ gs_external_appstream_refresh_sys (GsPlugin      *plugin,
        SoupSession *soup_session;
        guint status_code;
        gboolean file_written;
+       gconstpointer downloaded_data;
+       gsize downloaded_data_length;
        g_autofree gchar *tmp_file_path = NULL;
        g_autofree gchar *file_name = NULL;
        g_autofree gchar *local_mod_date = NULL;
@@ -102,6 +104,9 @@ gs_external_appstream_refresh_sys (GsPlugin      *plugin,
        g_autoptr(GFileIOStream) iostream = NULL;
        g_autoptr(GFile) tmp_file = NULL;
        g_autoptr(SoupMessage) msg = NULL;
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_autoptr(GBytes) bytes = NULL;
+#endif
 
        /* check age */
        file_name = g_path_get_basename (url);
@@ -120,14 +125,32 @@ gs_external_appstream_refresh_sys (GsPlugin      *plugin,
        if (local_mod_date != NULL) {
                g_debug ("Requesting contents of %s if modified since %s",
                         url, local_mod_date);
-               soup_message_headers_append (msg->request_headers,
+               soup_message_headers_append (
+#if SOUP_CHECK_VERSION(3, 0, 0)
+                                            soup_message_get_request_headers (msg),
+#else
+                                            msg->request_headers,
+#endif
                                             "If-Modified-Since",
                                             local_mod_date);
        }
 
        /* get the data */
        soup_session = gs_plugin_get_soup_session (plugin);
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       bytes = soup_session_send_and_read (soup_session, msg, cancellable, error);
+       if (bytes != NULL) {
+               downloaded_data = g_bytes_get_data (bytes, &downloaded_data_length);
+       } else {
+               downloaded_data = NULL;
+               downloaded_data_length = 0;
+       }
+       status_code = soup_message_get_status (msg);
+#else
        status_code = soup_session_send_message (soup_session, msg);
+       downloaded_data = msg->response_body ? msg->response_body->data : NULL;
+       downloaded_data_length = msg->response_body ? msg->response_body->length : 0;
+#endif
        if (status_code != SOUP_STATUS_OK) {
                if (status_code == SOUP_STATUS_NOT_MODIFIED) {
                        g_debug ("Not updating %s has not modified since %s",
@@ -169,9 +192,7 @@ gs_external_appstream_refresh_sys (GsPlugin      *plugin,
 
        /* write to file */
        outstream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
-       file_written = g_output_stream_write_all (outstream,
-                                                 msg->response_body->data,
-                                                 msg->response_body->length,
+       file_written = g_output_stream_write_all (outstream, downloaded_data, downloaded_data_length,
                                                  NULL, cancellable, error);
 
        /* close the file */
diff --git a/lib/gs-odrs-provider.c b/lib/gs-odrs-provider.c
index 00502e27c..4adba5418 100644
--- a/lib/gs-odrs-provider.c
+++ b/lib/gs-odrs-provider.c
@@ -475,24 +475,113 @@ gs_odrs_provider_parse_success (const gchar  *data,
        return TRUE;
 }
 
+#if SOUP_CHECK_VERSION(3, 0, 0)
+typedef struct _MessageData {
+       GInputStream *input_stream;
+       gssize length;
+       goffset read_from;
+} MessageData;
+
+static MessageData *
+message_data_new (GInputStream *input_stream,
+                 gssize length)
+{
+       MessageData *md;
+
+       md = g_slice_new0 (MessageData);
+       md->input_stream = g_object_ref (input_stream);
+       md->length = length;
+
+       if (G_IS_SEEKABLE (input_stream))
+               md->read_from = g_seekable_tell (G_SEEKABLE (input_stream));
+
+       return md;
+}
+
+static void
+message_data_free (gpointer ptr,
+                  GClosure *closure)
+{
+       MessageData *md = ptr;
+
+       if (md) {
+               g_object_unref (md->input_stream);
+               g_slice_free (MessageData, md);
+       }
+}
+
+static void
+g_odrs_provider_message_restarted_cb (SoupMessage *message,
+                                     gpointer user_data)
+{
+       MessageData *md = user_data;
+
+       if (G_IS_SEEKABLE (md->input_stream) && md->read_from != g_seekable_tell (G_SEEKABLE 
(md->input_stream)))
+               g_seekable_seek (G_SEEKABLE (md->input_stream), md->read_from, G_SEEK_SET, NULL, NULL);
+
+       soup_message_set_request_body (message, NULL, md->input_stream, md->length);
+}
+
+static void
+g_odrs_provider_set_message_request_body (SoupMessage *message,
+                                         const gchar *content_type,
+                                         gconstpointer data,
+                                         gsize length)
+{
+       MessageData *md;
+       GInputStream *input_stream;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (message));
+       g_return_if_fail (data != NULL);
+
+       input_stream = g_memory_input_stream_new_from_data (data, length, NULL);
+       md = message_data_new (input_stream, length);
+
+       g_signal_connect_data (message, "restarted",
+               G_CALLBACK (g_odrs_provider_message_restarted_cb), md, message_data_free, 0);
+
+       soup_message_set_request_body (message, content_type, input_stream, length);
+
+       g_object_unref (input_stream);
+}
+#endif
+
 static gboolean
 gs_odrs_provider_json_post (SoupSession  *session,
                             const gchar  *uri,
                             const gchar  *data,
+                           GCancellable *cancellable,
                             GError      **error)
 {
        guint status_code;
        g_autoptr(SoupMessage) msg = NULL;
-
+       gconstpointer downloaded_data;
+       gsize downloaded_data_length;
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_autoptr(GBytes) bytes = NULL;
+#endif
        /* create the GET data */
        g_debug ("Sending ODRS request to %s: %s", uri, data);
        msg = soup_message_new (SOUP_METHOD_POST, uri);
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_odrs_provider_set_message_request_body (msg, "application/json; charset=utf-8",
+                                                 data, strlen (data));
+       bytes = soup_session_send_and_read (session, msg, cancellable, error);
+       if (bytes == NULL)
+               return FALSE;
+
+       downloaded_data = g_bytes_get_data (bytes, &downloaded_data_length);
+       status_code = soup_message_get_status (msg);
+#else
        soup_message_set_request (msg, "application/json; charset=utf-8",
                                  SOUP_MEMORY_COPY, data, strlen (data));
 
        /* set sync request */
        status_code = soup_session_send_message (session, msg);
-       g_debug ("ODRS server returned status %u: %s", status_code, msg->response_body->data);
+       downloaded_data = msg->response_body ? msg->response_body->data : NULL;
+       downloaded_data_length = msg->response_body ? msg->response_body->length : 0;
+#endif
+       g_debug ("ODRS server returned status %u: %.*s", status_code, (gint) downloaded_data_length, (const 
gchar *) downloaded_data);
        if (status_code != SOUP_STATUS_OK) {
                g_warning ("Failed to set rating on ODRS: %s",
                           soup_status_get_phrase (status_code));
@@ -504,9 +593,7 @@ gs_odrs_provider_json_post (SoupSession  *session,
        }
 
        /* process returned JSON */
-       return gs_odrs_provider_parse_success (msg->response_body->data,
-                                              msg->response_body->length,
-                                              error);
+       return gs_odrs_provider_parse_success (downloaded_data, downloaded_data_length, error);
 }
 
 static GPtrArray *
@@ -654,11 +741,14 @@ gs_odrs_provider_get_compat_ids (GsApp *app)
 static GPtrArray *
 gs_odrs_provider_fetch_for_app (GsOdrsProvider  *self,
                                 GsApp           *app,
+                               GCancellable    *cancellable,
                                 GError         **error)
 {
        JsonNode *json_compat_ids;
        const gchar *version;
        guint status_code;
+       gconstpointer downloaded_data;
+       gsize downloaded_data_length;
        g_autofree gchar *cachefn_basename = NULL;
        g_autofree gchar *cachefn = NULL;
        g_autofree gchar *data = NULL;
@@ -669,6 +759,9 @@ gs_odrs_provider_fetch_for_app (GsOdrsProvider  *self,
        g_autoptr(JsonGenerator) json_generator = NULL;
        g_autoptr(JsonNode) json_root = NULL;
        g_autoptr(SoupMessage) msg = NULL;
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_autoptr(GBytes) bytes = NULL;
+#endif
 
        /* look in the cache */
        cachefn_basename = g_strdup_printf ("%s.json", gs_app_get_id (app));
@@ -734,13 +827,24 @@ gs_odrs_provider_fetch_for_app (GsOdrsProvider  *self,
        g_debug ("Updating ODRS cache for %s from %s to %s; request %s", gs_app_get_id (app),
                 uri, cachefn, data);
        msg = soup_message_new (SOUP_METHOD_POST, uri);
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_odrs_provider_set_message_request_body (msg, "application/json; charset=utf-8",
+                                                 data, strlen (data));
+       bytes = soup_session_send_and_read (self->session, msg, cancellable, error);
+       if (bytes == NULL)
+               return NULL;
+
+       downloaded_data = g_bytes_get_data (bytes, &downloaded_data_length);
+       status_code = soup_message_get_status (msg);
+#else
        soup_message_set_request (msg, "application/json; charset=utf-8",
                                  SOUP_MEMORY_COPY, data, strlen (data));
        status_code = soup_session_send_message (self->session, msg);
+       downloaded_data = msg->response_body ? msg->response_body->data : NULL;
+       downloaded_data_length = msg->response_body ? msg->response_body->length : 0;
+#endif
        if (status_code != SOUP_STATUS_OK) {
-               if (!gs_odrs_provider_parse_success (msg->response_body->data,
-                                                    msg->response_body->length,
-                                                    error))
+               if (!gs_odrs_provider_parse_success (downloaded_data, downloaded_data_length, error))
                        return NULL;
                /* not sure what to do here */
                g_set_error_literal (error,
@@ -750,18 +854,12 @@ gs_odrs_provider_fetch_for_app (GsOdrsProvider  *self,
                gs_utils_error_add_origin_id (error, self->cached_origin);
                return NULL;
        }
-       reviews = gs_odrs_provider_parse_reviews (self,
-                                                 msg->response_body->data,
-                                                 msg->response_body->length,
-                                                 error);
+       reviews = gs_odrs_provider_parse_reviews (self, downloaded_data, downloaded_data_length, error);
        if (reviews == NULL)
                return NULL;
 
        /* save to the cache */
-       if (!g_file_set_contents (cachefn,
-                                 msg->response_body->data,
-                                 msg->response_body->length,
-                                 error))
+       if (!g_file_set_contents (cachefn, downloaded_data, downloaded_data_length, error))
                return NULL;
 
        /* success */
@@ -778,7 +876,7 @@ gs_odrs_provider_refine_reviews (GsOdrsProvider  *self,
        g_autoptr(GPtrArray) reviews = NULL;
 
        /* get from server */
-       reviews = gs_odrs_provider_fetch_for_app (self, app, error);
+       reviews = gs_odrs_provider_fetch_for_app (self, app, cancellable, error);
        if (reviews == NULL)
                return FALSE;
        for (guint i = 0; i < reviews->len; i++) {
@@ -893,6 +991,7 @@ static gboolean
 gs_odrs_provider_vote (GsOdrsProvider  *self,
                        AsReview        *review,
                        const gchar     *uri,
+                      GCancellable    *cancellable,
                        GError         **error)
 {
        const gchar *tmp;
@@ -936,7 +1035,7 @@ gs_odrs_provider_vote (GsOdrsProvider  *self,
                return FALSE;
 
        /* send to server */
-       if (!gs_odrs_provider_json_post (self->session, uri, data, error))
+       if (!gs_odrs_provider_json_post (self->session, uri, data, cancellable, error))
                return FALSE;
 
        /* mark as voted */
@@ -1404,7 +1503,7 @@ gs_odrs_provider_submit_review (GsOdrsProvider  *self,
 
        /* POST */
        uri = g_strdup_printf ("%s/submit", self->review_server);
-       if (!gs_odrs_provider_json_post (self->session, uri, data, error))
+       if (!gs_odrs_provider_json_post (self->session, uri, data, cancellable, error))
                return FALSE;
 
        /* modify the local app */
@@ -1436,7 +1535,7 @@ gs_odrs_provider_report_review (GsOdrsProvider  *self,
 {
        g_autofree gchar *uri = NULL;
        uri = g_strdup_printf ("%s/report", self->review_server);
-       return gs_odrs_provider_vote (self, review, uri, error);
+       return gs_odrs_provider_vote (self, review, uri, cancellable, error);
 }
 
 /**
@@ -1461,7 +1560,7 @@ gs_odrs_provider_upvote_review (GsOdrsProvider  *self,
 {
        g_autofree gchar *uri = NULL;
        uri = g_strdup_printf ("%s/upvote", self->review_server);
-       return gs_odrs_provider_vote (self, review, uri, error);
+       return gs_odrs_provider_vote (self, review, uri, cancellable, error);
 }
 
 /**
@@ -1486,7 +1585,7 @@ gs_odrs_provider_downvote_review (GsOdrsProvider  *self,
 {
        g_autofree gchar *uri = NULL;
        uri = g_strdup_printf ("%s/downvote", self->review_server);
-       return gs_odrs_provider_vote (self, review, uri, error);
+       return gs_odrs_provider_vote (self, review, uri, cancellable, error);
 }
 
 /**
@@ -1511,7 +1610,7 @@ gs_odrs_provider_dismiss_review (GsOdrsProvider  *self,
 {
        g_autofree gchar *uri = NULL;
        uri = g_strdup_printf ("%s/dismiss", self->review_server);
-       return gs_odrs_provider_vote (self, review, uri, error);
+       return gs_odrs_provider_vote (self, review, uri, cancellable, error);
 }
 
 /**
@@ -1536,7 +1635,7 @@ gs_odrs_provider_remove_review (GsOdrsProvider  *self,
 {
        g_autofree gchar *uri = NULL;
        uri = g_strdup_printf ("%s/remove", self->review_server);
-       if (!gs_odrs_provider_vote (self, review, uri, error))
+       if (!gs_odrs_provider_vote (self, review, uri, cancellable, error))
                return FALSE;
 
        /* update the local app */
@@ -1565,10 +1664,15 @@ gs_odrs_provider_add_unvoted_reviews (GsOdrsProvider  *self,
 {
        guint status_code;
        guint i;
+       gconstpointer downloaded_data;
+       gsize downloaded_data_length;
        g_autofree gchar *uri = NULL;
        g_autoptr(GHashTable) hash = NULL;
        g_autoptr(GPtrArray) reviews = NULL;
        g_autoptr(SoupMessage) msg = NULL;
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_autoptr(GBytes) bytes = NULL;
+#endif
 
        /* create the GET data *with* the machine hash so we can later
         * review the application ourselves */
@@ -1577,11 +1681,20 @@ gs_odrs_provider_add_unvoted_reviews (GsOdrsProvider  *self,
                               self->user_hash,
                               setlocale (LC_MESSAGES, NULL));
        msg = soup_message_new (SOUP_METHOD_GET, uri);
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       bytes = soup_session_send_and_read (self->session, msg, cancellable, error);
+       if (bytes == NULL)
+               return FALSE;
+
+       downloaded_data = g_bytes_get_data (bytes, &downloaded_data_length);
+       status_code = soup_message_get_status (msg);
+#else
        status_code = soup_session_send_message (self->session, msg);
+       downloaded_data = msg->response_body ? msg->response_body->data : NULL;
+       downloaded_data_length = msg->response_body ? msg->response_body->length : 0;
+#endif
        if (status_code != SOUP_STATUS_OK) {
-               if (!gs_odrs_provider_parse_success (msg->response_body->data,
-                                                    msg->response_body->length,
-                                                    error))
+               if (!gs_odrs_provider_parse_success (downloaded_data, downloaded_data_length, error))
                        return FALSE;
                /* not sure what to do here */
                g_set_error_literal (error,
@@ -1591,11 +1704,8 @@ gs_odrs_provider_add_unvoted_reviews (GsOdrsProvider  *self,
                gs_utils_error_add_origin_id (error, self->cached_origin);
                return FALSE;
        }
-       g_debug ("odrs returned: %s", msg->response_body->data);
-       reviews = gs_odrs_provider_parse_reviews (self,
-                                                 msg->response_body->data,
-                                                 msg->response_body->length,
-                                                 error);
+       g_debug ("odrs returned: %.*s", (gint) downloaded_data_length, (const gchar *) downloaded_data);
+       reviews = gs_odrs_provider_parse_reviews (self, downloaded_data, downloaded_data_length, error);
        if (reviews == NULL)
                return FALSE;
 
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 8278bc2e9..b3dadcf8a 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -2977,9 +2977,9 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader)
                                                             (GDestroyNotify) g_object_unref);
 
        /* share a soup session (also disable the double-compression) */
-       plugin_loader->soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, gs_user_agent 
(),
-                                                           SOUP_SESSION_TIMEOUT, 10,
-                                                           NULL);
+       plugin_loader->soup_session = soup_session_new_with_options ("user-agent", gs_user_agent (),
+                                                                    "timeout", 10,
+                                                                    NULL);
 
        /* get the category manager */
        plugin_loader->category_manager = gs_category_manager_new ();
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index b75220f1e..07b44e207 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -932,6 +932,58 @@ gs_plugin_reload (GsPlugin *plugin)
        g_idle_add (gs_plugin_reload_cb, plugin);
 }
 
+#if SOUP_CHECK_VERSION(3, 0, 0)
+static GBytes * /* (transfer full) */
+gs_plugin_download_with_progress (GsPlugin *plugin,
+                                 GsApp *app,
+                                 SoupMessage *msg,
+                                 GInputStream *stream,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       g_autoptr(GByteArray) byte_array = NULL;
+       gsize nread, total_read, expected_length;
+       guint8 buffer[16384];
+       gboolean success = FALSE;
+
+       if (stream == NULL || !SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)) ||
+           g_cancellable_is_cancelled (cancellable))
+               return NULL;
+
+       byte_array = g_byte_array_new ();
+
+       total_read = 0;
+       expected_length = soup_message_headers_get_content_length (soup_message_get_response_headers (msg));
+
+       while (g_input_stream_read_all (stream, buffer, sizeof (buffer), &nread, cancellable, error)) {
+               if (!nread) {
+                       success = TRUE;
+                       break;
+               }
+               g_byte_array_append (byte_array, buffer, nread);
+               total_read += nread;
+               if (app != NULL && expected_length > 0) {
+                       /* calculate percentage */
+                       guint percentage = (guint) ((100 * total_read) / expected_length);
+                       g_debug ("%s progress: %u%%", gs_app_get_id (app), percentage);
+                       gs_app_set_progress (app, percentage);
+                       gs_plugin_status_update (plugin, app, GS_PLUGIN_STATUS_DOWNLOADING);
+               }
+               if (nread < sizeof (buffer)) {
+                       success = TRUE;
+                       break;
+               }
+       }
+
+       if (success) {
+               GBytes *bytes = g_byte_array_free_to_bytes (byte_array);
+               byte_array = NULL;
+               return bytes;
+       }
+
+       return NULL;
+}
+#else
 typedef struct {
        GsPlugin        *plugin;
        GsApp           *app;
@@ -980,6 +1032,7 @@ gs_plugin_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk,
                                 helper->app,
                                 GS_PLUGIN_STATUS_DOWNLOADING);
 }
+#endif
 
 /**
  * gs_plugin_download_data:
@@ -1003,8 +1056,14 @@ gs_plugin_download_data (GsPlugin *plugin,
                         GError **error)
 {
        GsPluginPrivate *priv = gs_plugin_get_instance_private (plugin);
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_autoptr(GInputStream) stream = NULL;
+       g_autoptr(GError) error_local = NULL;
+       GBytes *bytes;
+#else
        GsPluginDownloadHelper helper;
        guint status_code;
+#endif
        g_autoptr(SoupMessage) msg = NULL;
 
        g_return_val_if_fail (GS_IS_PLUGIN (plugin), NULL);
@@ -1015,7 +1074,9 @@ gs_plugin_download_data (GsPlugin *plugin,
        if (g_str_has_prefix (uri, "file://")) {
                gsize length = 0;
                g_autofree gchar *contents = NULL;
+#if !SOUP_CHECK_VERSION(3, 0, 0)
                g_autoptr(GError) error_local = NULL;
+#endif
                g_debug ("copying %s from plugin %s", uri, priv->name);
                if (!g_file_get_contents (uri + 7, &contents, &length, &error_local)) {
                        g_set_error (error,
@@ -1031,6 +1092,29 @@ gs_plugin_download_data (GsPlugin *plugin,
        /* remote */
        g_debug ("downloading %s from plugin %s", uri, priv->name);
        msg = soup_message_new (SOUP_METHOD_GET, uri);
+       if (msg == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_DOWNLOAD_FAILED,
+                            "failed to parse URI %s", uri);
+               return NULL;
+       }
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       stream = soup_session_send (priv->soup_session, msg, cancellable, &error_local);
+       bytes = gs_plugin_download_with_progress (plugin, app, msg, stream, cancellable, &error_local);
+       if (bytes == NULL) {
+               if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_propagate_error (error, error_local);
+               } else {
+                       g_set_error (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_DOWNLOAD_FAILED,
+                                    "failed to download %s: %s",
+                                    uri, error_local ? error_local->message : "Unknown error");
+               }
+       }
+       return bytes;
+#else
        if (app != NULL) {
                helper.plugin = plugin;
                helper.app = app;
@@ -1056,6 +1140,7 @@ gs_plugin_download_data (GsPlugin *plugin,
        }
        return g_bytes_new (msg->response_body->data,
                            (gsize) msg->response_body->length);
+#endif
 }
 
 /**
@@ -1082,9 +1167,16 @@ gs_plugin_download_file (GsPlugin *plugin,
                         GError **error)
 {
        GsPluginPrivate *priv = gs_plugin_get_instance_private (plugin);
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_autoptr(GInputStream) stream = NULL;
+       g_autoptr(GBytes) bytes = NULL;
+#else
        GsPluginDownloadHelper helper;
+#endif
        const gchar *new_etag;
        guint status_code;
+       gconstpointer downloaded_data = NULL;
+       gsize downloaded_data_length = 0;
        g_autoptr(GError) error_local = NULL;
        g_autoptr(SoupMessage) msg = NULL;
 
@@ -1127,6 +1219,23 @@ gs_plugin_download_file (GsPlugin *plugin,
                             "failed to parse URI %s", uri);
                return FALSE;
        }
+       if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+               g_autofree gchar *last_etag = gs_utils_get_file_etag (filename, cancellable);
+               if (last_etag != NULL && *last_etag != '\0') {
+#if SOUP_CHECK_VERSION(3, 0, 0)
+                       soup_message_headers_append (soup_message_get_request_headers (msg), "If-None-Match", 
last_etag);
+#else
+                       soup_message_headers_append (msg->request_headers, "If-None-Match", last_etag);
+#endif
+               }
+       }
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       stream = soup_session_send (priv->soup_session, msg, cancellable, &error_local);
+       bytes = gs_plugin_download_with_progress (plugin, app, msg, stream, cancellable, &error_local);
+       if (bytes != NULL)
+               downloaded_data = g_bytes_get_data (bytes, &downloaded_data_length);
+       status_code = soup_message_get_status (msg);
+#else
        if (app != NULL) {
                helper.plugin = plugin;
                helper.app = app;
@@ -1135,20 +1244,24 @@ gs_plugin_download_file (GsPlugin *plugin,
                                  G_CALLBACK (gs_plugin_download_chunk_cb),
                                  &helper);
        }
-       if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
-               g_autofree gchar *last_etag = gs_utils_get_file_etag (filename, cancellable);
-               if (last_etag != NULL && *last_etag != '\0')
-                       soup_message_headers_append (msg->request_headers, "If-None-Match", last_etag);
-       }
        status_code = soup_session_send_message (priv->soup_session, msg);
+       downloaded_data = msg->response_body ? msg->response_body->data : NULL;
+       downloaded_data_length = msg->response_body ? msg->response_body->length : 0;
+#endif
        if (status_code == SOUP_STATUS_NOT_MODIFIED)
                return TRUE;
        if (status_code != SOUP_STATUS_OK) {
                g_autoptr(GString) str = g_string_new (NULL);
                g_string_append (str, soup_status_get_phrase (status_code));
-               if (msg->response_body->data != NULL) {
+#if SOUP_CHECK_VERSION(3, 0, 0)
+               if (error_local != NULL) {
                        g_string_append (str, ": ");
-                       g_string_append (str, msg->response_body->data);
+                       g_string_append (str, error_local->message);
+               }
+#endif
+               if (downloaded_data != NULL && downloaded_data_length > 0) {
+                       g_string_append (str, ": ");
+                       g_string_append_len (str, downloaded_data, downloaded_data_length);
                }
                g_set_error (error,
                             GS_PLUGIN_ERROR,
@@ -1157,12 +1270,12 @@ gs_plugin_download_file (GsPlugin *plugin,
                             uri, str->str);
                return FALSE;
        }
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       g_clear_error (&error_local);
+#endif
        if (!gs_mkdir_parent (filename, error))
                return FALSE;
-       if (!g_file_set_contents (filename,
-                                 msg->response_body->data,
-                                 msg->response_body->length,
-                                 &error_local)) {
+       if (!g_file_set_contents (filename, downloaded_data, downloaded_data_length, &error_local)) {
                g_set_error (error,
                             GS_PLUGIN_ERROR,
                             GS_PLUGIN_ERROR_WRITE_FAILED,
@@ -1170,7 +1283,11 @@ gs_plugin_download_file (GsPlugin *plugin,
                             error_local->message);
                return FALSE;
        }
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       new_etag = soup_message_headers_get_one (soup_message_get_response_headers (msg), "ETag");
+#else
        new_etag = soup_message_headers_get_one (msg->response_headers, "ETag");
+#endif
        if (new_etag != NULL && *new_etag == '\0')
                new_etag = NULL;
        gs_utils_set_file_etag (filename, new_etag, cancellable);
diff --git a/lib/gs-remote-icon.c b/lib/gs-remote-icon.c
index 061863333..97ed254be 100644
--- a/lib/gs-remote-icon.c
+++ b/lib/gs-remote-icon.c
@@ -240,6 +240,7 @@ gs_icon_download (SoupSession   *session,
                   GCancellable  *cancellable,
                   GError       **error)
 {
+       guint status_code;
        g_autoptr(SoupMessage) msg = NULL;
        g_autoptr(GInputStream) stream = NULL;
        g_autoptr(GdkPixbuf) pixbuf = NULL;
@@ -258,14 +259,19 @@ gs_icon_download (SoupSession   *session,
        /* Send request synchronously and start reading the response. */
        stream = soup_session_send (session, msg, cancellable, error);
 
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       status_code = soup_message_get_status (msg);
+#else
+       status_code = msg->status_code;
+#endif
        if (stream == NULL) {
                return NULL;
-       } else if (msg->status_code != SOUP_STATUS_OK) {
+       } else if (status_code != SOUP_STATUS_OK) {
                g_set_error (error,
-                            SOUP_HTTP_ERROR,
-                            msg->status_code,
+                            G_IO_ERROR,
+                            G_IO_ERROR_FAILED,
                             "Failed to download icon %s: %s",
-                            uri, soup_status_get_phrase (msg->status_code));
+                            uri, soup_status_get_phrase (status_code));
                return NULL;
        }
 
diff --git a/lib/gs-utils.c b/lib/gs-utils.c
index ec4092ba0..1f1d4e00c 100644
--- a/lib/gs-utils.c
+++ b/lib/gs-utils.c
@@ -1015,19 +1015,19 @@ gs_utils_error_convert_appstream (GError **perror)
 gchar *
 gs_utils_get_url_scheme        (const gchar *url)
 {
-       g_autoptr(SoupURI) uri = NULL;
+       g_autoptr(GUri) uri = NULL;
 
        /* no data */
        if (url == NULL)
                return NULL;
 
        /* create URI from URL */
-       uri = soup_uri_new (url);
-       if (!SOUP_URI_IS_VALID (uri))
+       uri = g_uri_parse (url, SOUP_HTTP_URI_FLAGS, NULL);
+       if (!uri)
                return NULL;
 
        /* success */
-       return g_strdup (soup_uri_get_scheme (uri));
+       return g_strdup (g_uri_get_scheme (uri));
 }
 
 /**
@@ -1041,19 +1041,19 @@ gs_utils_get_url_scheme (const gchar *url)
 gchar *
 gs_utils_get_url_path (const gchar *url)
 {
-       g_autoptr(SoupURI) uri = NULL;
+       g_autoptr(GUri) uri = NULL;
        const gchar *host;
        const gchar *path;
 
-       uri = soup_uri_new (url);
-       if (!SOUP_URI_IS_VALID (uri))
+       uri = g_uri_parse (url, SOUP_HTTP_URI_FLAGS, NULL);
+       if (!uri)
                return NULL;
 
        /* foo://bar -> scheme: foo, host: bar, path: / */
        /* foo:bar -> scheme: foo, host: (empty string), path: /bar */
-       host = soup_uri_get_host (uri);
-       path = soup_uri_get_path (uri);
-       if (host != NULL && (strlen (host) > 0))
+       host = g_uri_get_host (uri);
+       path = g_uri_get_path (uri);
+       if (host != NULL && *host != '\0')
                path = host;
 
        /* trim any leading slashes */
diff --git a/lib/meson.build b/lib/meson.build
index 3b8c92339..78d32352e 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -124,6 +124,7 @@ pkg.generate(
     variables : [
       'gs_private_libdir=${libdir}/gnome-software',
       'plugindir=${gs_private_libdir}/plugins-' + gs_plugin_api_version,
+      'soupapiversion=' + libsoupapiversion
     ],
     install_dir : join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'),  # or it defaults to 
gs_private_libdir, which is wrong
 )
diff --git a/meson.build b/meson.build
index 274f4b4c6..4c81ca601 100644
--- a/meson.build
+++ b/meson.build
@@ -126,10 +126,17 @@ libxmlb = dependency('xmlb', version : '>= 0.1.7', fallback : ['libxmlb', 'libxm
 gio_unix = dependency('gio-unix-2.0', version : '>= 2.56.0')
 gmodule = dependency('gmodule-2.0')
 gtk = dependency('gtk4', version : '>= 4.2')
-glib = dependency('glib-2.0', version : '>= 2.55.0')
+glib = dependency('glib-2.0', version : '>= 2.66.0')
 json_glib = dependency('json-glib-1.0', version : '>= 1.2.0')
 libm = cc.find_library('m', required: false)
-libsoup = dependency('libsoup-2.4', version : '>= 2.52.0')
+if get_option('soup3')
+  libsoup = dependency('libsoup-3.0', version : '>= 3.0')
+  libsoupapiversion = '3.0'
+else
+  libsoup = dependency('libsoup-2.4', version : '>= 2.52.0')
+  libsoupapiversion = '2.4'
+  conf.set('SOUP_HTTP_URI_FLAGS', '(G_URI_FLAGS_HAS_PASSWORD | G_URI_FLAGS_ENCODED_PATH | 
G_URI_FLAGS_ENCODED_QUERY | G_URI_FLAGS_ENCODED_FRAGMENT | G_URI_FLAGS_SCHEME_NORMALIZE)')
+endif
 libadwaita = dependency('libadwaita-1',
   version: '>=1.0.0.alpha.3',
   fallback: ['libadwaita', 'libadwaita_dep'],
@@ -213,6 +220,14 @@ endif
 if get_option('flatpak')
   flatpak = dependency('flatpak', version : '>= 1.0.4')
   ostree = dependency('ostree-1')
+
+  flatpak_soupapiversion = flatpak.get_pkgconfig_variable('soupapiversion')
+  if flatpak_soupapiversion == ''
+    flatpak_soupapiversion = '2.4' # Pre libsoup3 support
+  endif
+  if flatpak_soupapiversion != libsoupapiversion
+    error('flatpak was built against a different API of libsoup. @0@ instead of 
@1@.'.format(flatpak_soupapiversion, libsoupapiversion))
+  endif
 endif
 
 if get_option('malcontent')
diff --git a/meson_options.txt b/meson_options.txt
index 587b9cca9..07cac95e2 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -20,3 +20,4 @@ option('default_featured_apps', type : 'boolean', value : true, description : 'e
 option('mogwai', type : 'boolean', value : false, description : 'enable metered data support using Mogwai')
 option('sysprof', type : 'feature', value : 'auto', description : 'enable sysprof-capture support for 
profiling')
 option('profile', type : 'string', value : '', description : 'Build with specified application ID')
+option('soup3', type : 'boolean', value : false, description : 'build with libsoup3')
diff --git a/plugins/core/gs-plugin-os-release.c b/plugins/core/gs-plugin-os-release.c
index 4b57378f7..01f6c0d3f 100644
--- a/plugins/core/gs-plugin-os-release.c
+++ b/plugins/core/gs-plugin-os-release.c
@@ -69,16 +69,16 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
        /* use libsoup to convert a URL */
        home_url = gs_os_release_get_home_url (os_release);
        if (home_url != NULL) {
-               g_autoptr(SoupURI) uri = NULL;
+               g_autoptr(GUri) uri = NULL;
 
                /* homepage */
                gs_app_set_url (self->app_system, AS_URL_KIND_HOMEPAGE, home_url);
 
                /* Build ID from the reverse-DNS URL and the ID and version. */
-               uri = soup_uri_new (home_url);
+               uri = g_uri_parse (home_url, SOUP_HTTP_URI_FLAGS, NULL);
                if (uri != NULL) {
                        g_auto(GStrv) split = NULL;
-                       const gchar *home_host = soup_uri_get_host (uri);
+                       const gchar *home_host = g_uri_get_host (uri);
                        split = g_strsplit_set (home_host, ".", -1);
                        if (g_strv_length (split) >= 2) {
                                g_autofree gchar *id = NULL;
diff --git a/plugins/fwupd/gs-plugin-fwupd.c b/plugins/fwupd/gs-plugin-fwupd.c
index f467e9339..c9937938f 100644
--- a/plugins/fwupd/gs-plugin-fwupd.c
+++ b/plugins/fwupd/gs-plugin-fwupd.c
@@ -241,8 +241,8 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
        g_autofree gchar *user_agent = NULL;
        /* use a custom user agent to provide the fwupd version */
        user_agent = fwupd_build_user_agent (PACKAGE_NAME, PACKAGE_VERSION);
-       soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent,
-                                                     SOUP_SESSION_TIMEOUT, 10,
+       soup_session = soup_session_new_with_options ("user-agent", user_agent,
+                                                     "timeout", 10,
                                                      NULL);
        soup_session_remove_feature_by_type (soup_session, SOUP_TYPE_CONTENT_DECODER);
 #endif
diff --git a/src/gs-application.c b/src/gs-application.c
index f128f9e81..0f1728e3c 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -16,7 +16,6 @@
 #include <glib/gi18n.h>
 #include <gio/gio.h>
 #include <gio/gdesktopappinfo.h>
-#include <libsoup/soup.h>
 
 #ifdef HAVE_PACKAGEKIT
 #include "gs-dbus-helper.h"
diff --git a/src/gs-details-page.c b/src/gs-details-page.c
index 5bdaaaf2c..98492ca53 100644
--- a/src/gs-details-page.c
+++ b/src/gs-details-page.c
@@ -76,7 +76,6 @@ struct _GsDetailsPage
        GsApp                   *app;
        GsApp                   *app_local_file;
        GsShell                 *shell;
-       SoupSession             *session;
        gboolean                 show_all_reviews;
        GSettings               *settings;
        GtkSizeGroup            *size_group_origin_popover;
@@ -2196,7 +2195,6 @@ gs_details_page_dispose (GObject *object)
        g_clear_object (&self->plugin_loader);
        g_clear_object (&self->cancellable);
        g_clear_object (&self->app_cancellable);
-       g_clear_object (&self->session);
        g_clear_object (&self->size_group_origin_popover);
        g_clear_object (&self->odrs_provider);
        g_clear_object (&self->app_info_monitor);
@@ -2360,9 +2358,6 @@ gs_details_page_init (GsDetailsPage *self)
 
        gtk_widget_init_template (GTK_WIDGET (self));
 
-       /* setup networking */
-       self->session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, gs_user_agent (),
-                                                      NULL);
        self->packaging_format_preference = g_hash_table_new_full (gs_details_page_strcase_hash, 
gs_details_page_strcase_equal, g_free, NULL);
        self->settings = g_settings_new ("org.gnome.software");
        g_signal_connect_swapped (self->settings, "changed",
diff --git a/src/gs-page.c b/src/gs-page.c
index 91d1c0b8d..c9d5803bb 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -102,7 +102,7 @@ gs_page_show_update_message (GsPageHelper *helper, AsScreenshot *ss)
                g_autoptr(SoupSession) soup_session = NULL;
 
                /* load screenshot */
-               soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
+               soup_session = soup_session_new_with_options ("user-agent",
                                                              gs_user_agent (), NULL);
                ssimg = gs_screenshot_image_new (soup_session);
                gs_screenshot_image_set_screenshot (GS_SCREENSHOT_IMAGE (ssimg), ss);
@@ -373,7 +373,7 @@ gs_page_needs_user_action (GsPageHelper *helper, AsScreenshot *ss)
        gtk_widget_set_sensitive (helper->button_install, FALSE);
 
        /* load screenshot */
-       soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
+       soup_session = soup_session_new_with_options ("user-agent",
                                                      gs_user_agent (), NULL);
        ssimg = gs_screenshot_image_new (soup_session);
        gs_screenshot_image_set_screenshot (GS_SCREENSHOT_IMAGE (ssimg), ss);
diff --git a/src/gs-repo-row.c b/src/gs-repo-row.c
index bbf67c194..e07cb946d 100644
--- a/src/gs-repo-row.c
+++ b/src/gs-repo-row.c
@@ -219,11 +219,11 @@ gs_repo_row_set_repo (GsRepoRow *self, GsApp *repo)
 
        tmp = gs_app_get_url (repo, AS_URL_KIND_HOMEPAGE);
        if (tmp != NULL && *tmp != '\0') {
-               g_autoptr(SoupURI) uri = NULL;
+               g_autoptr(GUri) uri = NULL;
 
-               uri = soup_uri_new (tmp);
-               if (uri && soup_uri_get_host (uri) != NULL && *soup_uri_get_host (uri) != '\0') {
-                       gtk_label_set_label (GTK_LABEL (priv->hostname_label), soup_uri_get_host (uri));
+               uri = g_uri_parse (tmp, SOUP_HTTP_URI_FLAGS, NULL);
+               if (uri && g_uri_get_host (uri) != NULL && *g_uri_get_host (uri) != '\0') {
+                       gtk_label_set_label (GTK_LABEL (priv->hostname_label), g_uri_get_host (uri));
                        gtk_widget_set_visible (priv->hostname_label, TRUE);
                }
        }
diff --git a/src/gs-screenshot-carousel.c b/src/gs-screenshot-carousel.c
index 3a93053f0..f9051892d 100644
--- a/src/gs-screenshot-carousel.c
+++ b/src/gs-screenshot-carousel.c
@@ -335,7 +335,7 @@ gs_screenshot_carousel_init (GsScreenshotCarousel *self)
 #endif
 
        /* setup networking */
-       self->session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, gs_user_agent (),
+       self->session = soup_session_new_with_options ("user-agent", gs_user_agent (),
                                                       NULL);
 }
 
diff --git a/src/gs-screenshot-image.c b/src/gs-screenshot-image.c
index 374e57171..94550d9fd 100644
--- a/src/gs-screenshot-image.c
+++ b/src/gs-screenshot-image.c
@@ -31,6 +31,9 @@ struct _GsScreenshotImage
        GSettings       *settings;
        SoupSession     *session;
        SoupMessage     *message;
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       GCancellable    *cancellable;
+#endif
        gchar           *filename;
        const gchar     *current_image;
        guint            width;
@@ -303,37 +306,78 @@ gs_screenshot_image_save_downloaded_img (GsScreenshotImage *ssimg,
 }
 
 static void
+#if SOUP_CHECK_VERSION(3, 0, 0)
+gs_screenshot_image_complete_cb (GObject *source_object,
+                                GAsyncResult *result,
+                                gpointer user_data)
+#else
 gs_screenshot_image_complete_cb (SoupSession *session,
                                 SoupMessage *msg,
                                 gpointer user_data)
+#endif
 {
        g_autoptr(GsScreenshotImage) ssimg = GS_SCREENSHOT_IMAGE (user_data);
        gboolean ret;
        g_autoptr(GError) error = NULL;
        g_autoptr(GdkPixbuf) pixbuf = NULL;
        g_autoptr(GInputStream) stream = NULL;
+       guint status_code;
+
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       SoupMessage *msg;
+
+       stream = soup_session_send_finish (SOUP_SESSION (source_object), result, &error);
+       if (stream == NULL) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_warning ("Failed to download screenshot: %s", error->message);
+                       gs_screenshot_image_stop_spinner (ssimg);
+                       gs_screenshot_image_set_error (ssimg, _("Screenshot not found"));
+               }
+               return;
+       }
 
+       msg = soup_session_get_async_result_message (SOUP_SESSION (source_object), result);
+       status_code = soup_message_get_status (msg);
+#else
+       status_code = msg->status_code;
+#endif
        if (ssimg->load_timeout_id) {
                g_source_remove (ssimg->load_timeout_id);
                ssimg->load_timeout_id = 0;
        }
 
        /* return immediately if the message was cancelled or if we're in destruction */
-       if (msg->status_code == SOUP_STATUS_CANCELLED || ssimg->session == NULL)
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       if (ssimg->session == NULL)
+#else
+       if (status_code == SOUP_STATUS_CANCELLED || ssimg->session == NULL)
+#endif
                return;
 
-       if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) {
+       if (status_code == SOUP_STATUS_NOT_MODIFIED) {
                g_debug ("screenshot has not been modified");
                as_screenshot_show_image (ssimg);
                gs_screenshot_image_stop_spinner (ssimg);
                return;
        }
-       if (msg->status_code != SOUP_STATUS_OK) {
+       if (status_code != SOUP_STATUS_OK) {
                /* Ignore failures due to being offline */
-               if (msg->status_code != SOUP_STATUS_CANT_RESOLVE)
+#if SOUP_CHECK_VERSION(3, 0, 0)
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE) &&
+                   !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE)) {
+#else
+               if (status_code != SOUP_STATUS_CANT_RESOLVE) {
+#endif
+                       const gchar *reason_phrase;
+#if SOUP_CHECK_VERSION(3, 0, 0)
+                       reason_phrase = soup_message_get_reason_phrase (msg);
+#else
+                       reason_phrase = msg->reason_phrase;
+#endif
                        g_warning ("Result of screenshot downloading attempt with "
-                                  "status code '%u': %s", msg->status_code,
-                                  msg->reason_phrase);
+                                  "status code '%u': %s", status_code,
+                                  reason_phrase);
+               }
                gs_screenshot_image_stop_spinner (ssimg);
                /* if we're already showing an image, then don't set the error
                 * as having an image (even if outdated) is better */
@@ -345,6 +389,7 @@ gs_screenshot_image_complete_cb (SoupSession *session,
                return;
        }
 
+#if !SOUP_CHECK_VERSION(3, 0, 0)
        /* create a buffer with the data */
        stream = g_memory_input_stream_new_from_data (msg->response_body->data,
                                                      msg->response_body->length,
@@ -353,6 +398,7 @@ gs_screenshot_image_complete_cb (SoupSession *session,
                gs_screenshot_image_stop_spinner (ssimg);
                return;
        }
+#endif
 
        /* load the image */
        pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
@@ -366,10 +412,10 @@ gs_screenshot_image_complete_cb (SoupSession *session,
        if (ssimg->width == G_MAXUINT || ssimg->height == G_MAXUINT ||
            (ssimg->width * ssimg->scale == (guint) gdk_pixbuf_get_width (pixbuf) &&
             ssimg->height * ssimg->scale == (guint) gdk_pixbuf_get_height (pixbuf))) {
-               ret = g_file_set_contents (ssimg->filename,
-                                          msg->response_body->data,
-                                          msg->response_body->length,
-                                          &error);
+               ret = gs_pixbuf_save_filename (pixbuf, ssimg->filename,
+                                              gdk_pixbuf_get_width (pixbuf),
+                                              gdk_pixbuf_get_height (pixbuf),
+                                              &error);
                if (!ret) {
                        gs_screenshot_image_set_error (ssimg, error->message);
                        return;
@@ -450,7 +496,12 @@ gs_screenshot_soup_msg_set_modified_request (SoupMessage *msg, GFile *file)
        date_time = g_date_time_new_from_timeval_local (&time_val);
 #endif
        mod_date = g_date_time_format (date_time, "%a, %d %b %Y %H:%M:%S %Z");
-       soup_message_headers_append (msg->request_headers,
+       soup_message_headers_append (
+#if SOUP_CHECK_VERSION(3, 0, 0)
+                                    soup_message_get_request_headers (msg),
+#else
+                                    msg->request_headers,
+#endif
                                     "If-Modified-Since",
                                     mod_date);
 }
@@ -476,7 +527,7 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
        g_autofree gchar *cache_kind = NULL;
        g_autofree gchar *cachefn_thumb = NULL;
        g_autofree gchar *sizedir = NULL;
-       g_autoptr(SoupURI) base_uri = NULL;
+       g_autoptr(GUri) base_uri = NULL;
 
        g_return_if_fail (GS_IS_SCREENSHOT_IMAGE (ssimg));
 
@@ -587,8 +638,12 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
 
        /* download file */
        g_debug ("downloading %s to %s", url, ssimg->filename);
-       base_uri = soup_uri_new (url);
-       if (base_uri == NULL || !SOUP_URI_VALID_FOR_HTTP (base_uri)) {
+       base_uri = g_uri_parse (url, SOUP_HTTP_URI_FLAGS, NULL);
+       if (base_uri == NULL ||
+           (g_strcmp0 (g_uri_get_scheme (base_uri), "http") != 0 &&
+            g_strcmp0 (g_uri_get_scheme (base_uri), "https") != 0) ||
+           g_uri_get_host (base_uri) == NULL ||
+           g_uri_get_path (base_uri) == NULL) {
                /* TRANSLATORS: this is when we try to download a screenshot
                 * that was not a valid URL */
                gs_screenshot_image_set_error (ssimg, _("Screenshot not valid"));
@@ -602,13 +657,25 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
 
        /* cancel any previous messages */
        if (ssimg->message != NULL) {
+#if SOUP_CHECK_VERSION(3, 0, 0)
+               g_cancellable_cancel (ssimg->cancellable);
+               g_clear_object (&ssimg->cancellable);
+#else
                soup_session_cancel_message (ssimg->session,
                                             ssimg->message,
                                             SOUP_STATUS_CANCELLED);
+#endif
                g_clear_object (&ssimg->message);
        }
 
+#if SOUP_CHECK_VERSION(3, 0, 0)
        ssimg->message = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
+#else
+       {
+       g_autofree gchar *uri_str = g_uri_to_string (base_uri);
+       ssimg->message = soup_message_new (SOUP_METHOD_GET, uri_str);
+       }
+#endif
        if (ssimg->message == NULL) {
                /* TRANSLATORS: this is when networking is not available */
                gs_screenshot_image_set_error (ssimg, _("Screenshot not available"));
@@ -626,10 +693,16 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                gs_screenshot_show_spinner_cb, ssimg);
 
        /* send async */
+#if SOUP_CHECK_VERSION(3, 0, 0)
+       ssimg->cancellable = g_cancellable_new ();
+       soup_session_send_async (ssimg->session, ssimg->message, G_PRIORITY_DEFAULT, ssimg->cancellable,
+                                gs_screenshot_image_complete_cb, g_object_ref (ssimg));
+#else
        soup_session_queue_message (ssimg->session,
                                    g_object_ref (ssimg->message) /* transfer full */,
                                    gs_screenshot_image_complete_cb,
                                    g_object_ref (ssimg));
+#endif
 }
 
 gboolean
@@ -661,9 +734,14 @@ gs_screenshot_image_dispose (GObject *object)
        }
 
        if (ssimg->message != NULL) {
+#if SOUP_CHECK_VERSION(3, 0, 0)
+               g_cancellable_cancel (ssimg->cancellable);
+               g_clear_object (&ssimg->cancellable);
+#else
                soup_session_cancel_message (ssimg->session,
                                             ssimg->message,
                                             SOUP_STATUS_CANCELLED);
+#endif
                g_clear_object (&ssimg->message);
        }
        gs_widget_remove_all (GTK_WIDGET (ssimg), NULL);


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