Blob Blame History Raw
From 920380afbb8776bc763737d0cc6cc8f894298b1e Mon Sep 17 00:00:00 2001
From: marcin <marcin@ipv8.pl>
Date: Sun, 7 Aug 2022 03:57:25 +0200
Subject: [PATCH] Preliminary port to libsoup-3.0 (patch v2)

---
 meson.build            |  2 +-
 src/cm-client.c        |  7 ++--
 src/cm-net.c           | 80 +++++++++++-------------------------------
 src/cm-utils-private.h |  3 --
 src/cm-utils.c         | 58 +++++++++---------------------
 5 files changed, 41 insertions(+), 109 deletions(-)

diff --git a/meson.build b/meson.build
index 295633a..f0ea89b 100644
--- a/meson.build
+++ b/meson.build
@@ -112,7 +112,7 @@ src_inc = include_directories('src')
 gio_dep = dependency('gio-2.0', version: '>= 2.66')
 cmatrix_deps = [
   dependency('libgcrypt'),
-  dependency('libsoup-2.4'),
+  dependency('libsoup-3.0'),
   dependency('json-glib-1.0'),
   dependency('sqlite3', version: '>=3.26.0'),
   libolm_dep,
diff --git a/src/cm-client.c b/src/cm-client.c
index 0cb0fc8..4b54b3a 100644
--- a/src/cm-client.c
+++ b/src/cm-client.c
@@ -241,9 +241,8 @@ handle_matrix_glitches (CmClient *self,
    * The G_RESOLVER_ERROR may be suggesting that the hostname is wrong, but we don't
    * know if it's network/DNS/Proxy error. So keep retrying.
    */
-  if ((error->domain == SOUP_HTTP_ERROR &&
-       error->code <= SOUP_STATUS_TLS_FAILED &&
-       error->code > SOUP_STATUS_CANCELLED) ||
+  if (error->domain == SOUP_TLD_ERROR ||
+      error->domain == G_TLS_ERROR ||
       g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE) ||
       g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) ||
       /* Should we handle connection_refused, or just keep it for localhost? */
@@ -947,7 +946,7 @@ gboolean
 cm_client_set_homeserver (CmClient   *self,
                           const char *homeserver)
 {
-  g_autoptr(SoupURI) uri = NULL;
+  g_autoptr(GUri) uri = NULL;
   GString *server;
 
   g_return_val_if_fail (CM_IS_CLIENT (self), FALSE);
diff --git a/src/cm-net.c b/src/cm-net.c
index 8cca289..4eaa52a 100644
--- a/src/cm-net.c
+++ b/src/cm-net.c
@@ -182,7 +182,8 @@ queue_data (CmNet      *self,
             GTask      *task)
 {
   g_autoptr(SoupMessage) message = NULL;
-  g_autoptr(SoupURI) uri = NULL;
+  g_autoptr(GUri) uri = NULL;
+  g_autoptr(GBytes) content_data = NULL;
   GCancellable *cancellable;
   SoupMessagePriority msg_priority;
   int priority = 0;
@@ -196,20 +197,20 @@ queue_data (CmNet      *self,
             method == SOUP_METHOD_POST ||
             method == SOUP_METHOD_PUT);
 
-  uri = soup_uri_new (self->homeserver);
-  soup_uri_set_path (uri, uri_path);
+  uri = g_uri_parse (self->homeserver, SOUP_HTTP_URI_FLAGS, NULL);
+  uri = soup_uri_copy (uri, SOUP_URI_PATH, uri_path, SOUP_URI_NONE);
 
   if (self->access_token) {
     if (!query)
       query = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
     g_hash_table_replace (query, g_strdup ("access_token"), g_strdup (self->access_token));
-    soup_uri_set_query_from_form (uri, query);
+    uri = soup_uri_copy(uri, SOUP_URI_QUERY, soup_form_encode_hash(query), SOUP_URI_NONE);
     g_hash_table_unref (query);
   }
 
   message = soup_message_new_from_uri (method, uri);
-  soup_message_headers_append (message->request_headers, "Accept-Encoding", "gzip");
+  soup_message_headers_append (soup_message_get_request_headers(message), "Accept-Encoding", "gzip");
 
   priority = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "priority"));
 
@@ -226,12 +227,14 @@ queue_data (CmNet      *self,
 
   soup_message_set_priority (message, msg_priority);
 
-  if (data)
-    soup_message_set_request (message, "application/json", SOUP_MEMORY_TAKE, data, size);
+  if (data) {
+    content_data = g_bytes_new_static (data, size);
+    soup_message_set_request_body_from_bytes (message, "application/json", content_data);
+  }
 
   cancellable = g_task_get_cancellable (task);
   g_task_set_task_data (task, g_object_ref (message), g_object_unref);
-  soup_session_send_async (self->soup_session, message, cancellable,
+  soup_session_send_async (self->soup_session, message, msg_priority, cancellable,
                            session_send_cb, task);
 }
 
@@ -324,7 +327,7 @@ cm_net_get_access_token (CmNet *self)
  * @size: The @data size in bytes
  * @uri_path: A string of the matrix uri path
  * @method: An interned string for GET, PUT, POST, etc.
- * @query: (nullable): A query to pass to internal #SoupURI
+ * @query: (nullable): A query to pass to internal #GUri
  * @cancellable: (nullable): A #GCancellable
  * @callback: The callback to run when completed
  * @user_data: user data for @callback
@@ -375,7 +378,7 @@ cm_net_send_data_async (CmNet               *self,
  * @object: (nullable) (transfer full): The data to send
  * @uri_path: A string of the matrix uri path
  * @method: An interned string for GET, PUT, POST, etc.
- * @query: (nullable): A query to pass to internal #SoupURI
+ * @query: (nullable): A query to pass to internal #GUri
  * @cancellable: (nullable): A #GCancellable
  * @callback: The callback to run when completed
  * @user_data: user data for @callback
@@ -477,7 +480,7 @@ cm_net_get_file_async (CmNet                 *self,
   g_object_set_data (G_OBJECT (task), "file", enc_file);
   g_object_set_data_full (G_OBJECT (task), "msg", msg, g_object_unref);
 
-  soup_session_send_async (self->file_session, msg, cancellable,
+  soup_session_send_async (self->file_session, msg, 0, cancellable,
                            net_get_file_stream_cb, task);
 }
 
@@ -531,42 +534,10 @@ put_file_async_cb (GObject      *obj,
     }
 }
 
-static void
-put_file_chunk (GTask       *task,
-                SoupMessage *msg)
-{
-  CmNet *self;
-  GInputStream *stream;
-  char buffer[8 * 1024];
-  gssize n_read;
-
-  g_assert (G_IS_TASK (task));
-  g_assert (SOUP_IS_MESSAGE (msg));
-
-  self = g_task_get_source_object (task);
-  g_assert (CM_IS_NET (self));
-
-  stream = g_object_get_data (G_OBJECT (task), "stream");
-  n_read = g_input_stream_read (stream, buffer, 8 * 1024, NULL, NULL);
-
-  if (n_read == 0)
-    {
-      soup_message_body_complete (msg->request_body);
-    }
-  else if (n_read == -1)
-    {
-      soup_session_cancel_message (self->file_session, msg, SOUP_STATUS_CANCELLED);
-    }
-  else
-    {
-      soup_message_body_append (msg->request_body, SOUP_MEMORY_COPY, buffer, n_read);
-    }
-}
-
 static void
 wrote_body_data_cb (GTask       *task,
                     SoupMessage *msg,
-                    SoupBuffer  *chunk)
+                    guint       chunk_size)
 {
   GFileProgressCallback progress_cb;
   gpointer progress_user_data;
@@ -614,18 +585,13 @@ cm_net_put_file_async (CmNet                 *self,
 
   url = g_strconcat (self->homeserver, "/_matrix/media/r0/upload", NULL);
   msg = soup_message_new (SOUP_METHOD_POST, url);
-  soup_uri_set_query_from_form (soup_message_get_uri (msg), query);
+  soup_message_set_uri(msg, soup_uri_copy(soup_message_get_uri(msg), SOUP_URI_QUERY, soup_form_encode_hash(query), SOUP_URI_NONE));
 
   /* We're uploading files in chunk */
-  soup_message_headers_set_encoding (msg->request_headers, SOUP_ENCODING_CHUNKED);
-  soup_message_body_set_accumulate (msg->request_body, FALSE);
-  soup_message_headers_set_content_length (msg->request_headers,
-                                           cm_input_stream_get_size (cm_stream));
-  soup_message_headers_set_content_type (msg->request_headers,
-                                         cm_input_stream_get_content_type (cm_stream), NULL);
-
-  /* Use this once we port to libsoup-3 */
-  /* soup_message_set_request_body (msg, "fixme", G_INPUT_STREAM (cm_stream), -1); */
+  soup_message_set_request_body (msg,
+                                 cm_input_stream_get_content_type (cm_stream),
+                                 G_INPUT_STREAM (cm_stream),
+                                 cm_input_stream_get_size (cm_stream));
 
   g_task_set_task_data (task, g_object_ref (file), g_object_unref);
   g_object_set_data_full (G_OBJECT (task), "msg", msg, g_object_unref);
@@ -634,15 +600,11 @@ cm_net_put_file_async (CmNet                 *self,
   local_task = g_task_new (self, cancellable, put_file_async_cb, self);
   g_task_set_task_data (local_task, task, g_object_unref);
 
-  g_signal_connect_object (msg, "wrote-headers",
-                           G_CALLBACK (put_file_chunk), task, G_CONNECT_SWAPPED);
-  g_signal_connect_object (msg, "wrote-chunk",
-                           G_CALLBACK (put_file_chunk), task, G_CONNECT_SWAPPED);
   if (progress_callback)
     g_signal_connect_object (msg, "wrote-body-data",
                              G_CALLBACK (wrote_body_data_cb), task, G_CONNECT_SWAPPED);
 
-  soup_session_send_async (self->file_session, msg, cancellable,
+  soup_session_send_async (self->file_session, msg, 0, cancellable,
                            session_send_cb, local_task);
 }
 
diff --git a/src/cm-utils-private.h b/src/cm-utils-private.h
index 50694b9..669d250 100644
--- a/src/cm-utils-private.h
+++ b/src/cm-utils-private.h
@@ -31,9 +31,6 @@ JsonObject   *cm_utils_json_object_get_object   (JsonObject          *object,
                                                  const char          *member);
 JsonArray    *cm_utils_json_object_get_array    (JsonObject          *object,
                                                  const char          *member);
-
-JsonObject   *cm_utils_get_message_json_object  (SoupMessage         *message,
-                                                 const char          *member);
 void          cm_utils_clear                    (char                *buffer,
                                                  size_t               length);
 void          cm_utils_free_buffer              (char                *buffer);
diff --git a/src/cm-utils.c b/src/cm-utils.c
index 7cebce3..42894ec 100644
--- a/src/cm-utils.c
+++ b/src/cm-utils.c
@@ -241,16 +241,16 @@ cm_utils_home_server_valid (const char *homeserver)
   if (homeserver)
     {
       g_autofree char *server = NULL;
-      g_autoptr(SoupURI) uri = NULL;
+      g_autoptr(GUri) uri = NULL;
 
       if (!strstr (homeserver, "//"))
         server = g_strconcat ("https://", homeserver, NULL);
 
-      uri = soup_uri_new (server ?: homeserver);
+      uri = g_uri_parse (server ?: homeserver, SOUP_HTTP_URI_FLAGS, NULL);
 
-      valid = SOUP_URI_VALID_FOR_HTTP (uri);
+      valid = !!uri;
       /* We need an absolute path URI */
-      valid = valid && *uri->host && g_str_equal (soup_uri_get_path (uri), "/");
+      valid = valid && *g_uri_get_host(uri) && g_str_equal (g_uri_get_path (uri), "/");
     }
 
   return valid;
@@ -465,38 +465,6 @@ cm_utils_json_object_get_array (JsonObject *object,
   return NULL;
 }
 
-JsonObject *
-cm_utils_get_message_json_object (SoupMessage *message,
-                                  const char  *member)
-{
-  g_autoptr(JsonParser) parser = NULL;
-  g_autoptr(SoupBuffer) buffer = NULL;
-  JsonObject *object = NULL;
-  gboolean is_json;
-
-  if (!message || !message->response_body)
-    return NULL;
-
-  buffer = soup_message_body_flatten (message->response_body);
-  parser = json_parser_new ();
-  is_json = json_parser_load_from_data (parser, buffer->data, buffer->length, NULL);
-
-  if (is_json)
-{
-    JsonNode *root;
-
-    root = json_parser_get_root (parser);
-
-    if (root && JSON_NODE_HOLDS_OBJECT (root))
-      object = json_node_get_object (root);
-
-    if (member && object)
-      object = json_object_get_object_member (object, member);
-  }
-
-  return object ? json_object_ref (object) : NULL;
-}
-
 static void
 load_from_stream_cb (JsonParser   *parser,
                      GAsyncResult *result,
@@ -575,11 +543,8 @@ uri_file_read_cb (GObject      *object,
     return;
   }
 
-  soup_message_get_https_status (message, NULL, &err_flags);
-
   if (message &&
-      soup_message_get_https_status (message, NULL, &err_flags) &&
-      err_flags)
+      (err_flags = soup_message_get_tls_peer_certificate_errors (message)))
 {
     guint timeout_id, timeout;
 
@@ -624,6 +589,14 @@ message_network_event_cb (SoupMessage        *msg,
   g_object_set_data_full (user_data, "address", address, g_object_unref);
 }
 
+static gboolean
+accept_certificate_callback (SoupMessage *msg, GTlsCertificate *certificate,
+                             GTlsCertificateFlags tls_errors, gpointer user_data)
+{
+    // Returning TRUE trusts it anyway.
+    return TRUE;
+}
+
 void
 cm_utils_read_uri_async (const char          *uri,
                          guint                timeout,
@@ -670,9 +643,10 @@ cm_utils_read_uri_async (const char          *uri,
                            G_CALLBACK (message_network_event_cb), task,
                            G_CONNECT_AFTER);
   session = soup_session_new ();
-  g_object_set (G_OBJECT (session), SOUP_SESSION_SSL_STRICT, FALSE, NULL);
+  /* Accept invalid certificates */
+  g_signal_connect (message, "accept-certificate", G_CALLBACK (accept_certificate_callback), NULL);
 
-  soup_session_send_async (session, message, cancel,
+  soup_session_send_async (session, message, 0, cancel,
                            uri_file_read_cb,
                            g_steal_pointer (&task));
 }
-- 
2.35.1