From b6cb98ee0f1fefc5831d9e3b63b727414a750567 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 7 Jun 2022 09:43:17 +0100 Subject: Port from libsoup to libcurl The former bumped ABI, and all sorts of crazy happens when you link in libappstream-glib into a process with the 'other' ABI. It seems the universe has settled on curl as a dep; do the same. --- README.md | 2 +- client/as-util.c | 69 +++++++++++++++++------------ client/meson.build | 12 +++--- contrib/ci/Dockerfile-fedora | 2 +- contrib/libappstream-glib.spec.in | 4 +- libappstream-builder/meson.build | 5 +-- libappstream-glib/as-app-validate.c | 86 ++++++++++++++++--------------------- libappstream-glib/as-utils.c | 1 - libappstream-glib/meson.build | 4 +- meson.build | 4 +- 10 files changed, 94 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 25924ce..e7d3b43 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ copy. To do the latter just do: dnf install docbook-utils gettext-devel glib-devel \ gobject-introspection-devel gperf gtk-doc gtk3-devel \ - json-glib-devel libarchive-devel libsoup-devel \ + json-glib-devel libarchive-devel libcurl-devel \ libstemmer-devel libuuid-devel libyaml-devel \ meson rpm-devel mkdir build && cd build diff --git a/client/as-util.c b/client/as-util.c index b8b52fc..4c3fdaa 100644 --- a/client/as-util.c +++ b/client/as-util.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -38,6 +38,7 @@ typedef struct { GMainLoop *loop; GCancellable *cancellable; AsProfile *profile; + CURL *curl; } AsUtilPrivate; typedef gboolean (*AsUtilPrivateCb) (AsUtilPrivate *util, @@ -3370,6 +3371,15 @@ as_util_mirror_screenshots_app_file (AsApp *app, return TRUE; } +static size_t +as_util_download_write_callback_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + GByteArray *buf = (GByteArray *)userdata; + gsize realsize = size * nmemb; + g_byte_array_append(buf, (const guint8 *)ptr, realsize); + return realsize; +} + static gboolean as_util_mirror_screenshots_app_url (AsUtilPrivate *priv, AsApp *app, @@ -3379,16 +3389,15 @@ as_util_mirror_screenshots_app_url (AsUtilPrivate *priv, const gchar *output_dir, GError **error) { + CURLcode res; gboolean is_default; gboolean ret = TRUE; - SoupStatus status; + gchar errbuf[CURL_ERROR_SIZE] = {'\0'}; g_autofree gchar *basename = NULL; g_autofree gchar *cache_filename = NULL; g_autoptr(AsImage) im = NULL; g_autoptr(AsScreenshot) ss = NULL; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupSession) session = NULL; - g_autoptr(SoupURI) uri = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new(); /* fonts screenshots are auto-generated */ if (as_app_get_kind (app) == AS_APP_KIND_FONT) { @@ -3405,13 +3414,6 @@ as_util_mirror_screenshots_app_url (AsUtilPrivate *priv, return TRUE; } - /* set up networking */ - session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, "appstream-util", - SOUP_SESSION_TIMEOUT, 10, - NULL); - soup_session_add_feature_by_type (session, - SOUP_TYPE_PROXY_RESOLVER_DEFAULT); - /* download to cache if not already added */ basename = g_path_get_basename (url); cache_filename = g_strdup_printf ("%s/%s-%s", @@ -3430,30 +3432,36 @@ as_util_mirror_screenshots_app_url (AsUtilPrivate *priv, "file:// URLs like %s are not supported", url); return FALSE; } - uri = soup_uri_new (url); - if (uri == NULL) { - g_set_error (error, - AS_ERROR, - AS_ERROR_FAILED, - "Could not parse '%s' as a URL", url); - return FALSE; - } - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); as_util_app_log (app, "Downloading %s", url); - status = soup_session_send_message (session, msg); - if (status != SOUP_STATUS_OK) { + + (void)curl_easy_setopt(priv->curl, CURLOPT_URL, url); + (void)curl_easy_setopt(priv->curl, CURLOPT_ERRORBUFFER, errbuf); + (void)curl_easy_setopt(priv->curl, + CURLOPT_WRITEFUNCTION, + as_util_download_write_callback_cb); + (void)curl_easy_setopt(priv->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform(priv->curl); + if (res != CURLE_OK) { + if (errbuf[0] != '\0') { + g_set_error (error, + AS_ERROR, + AS_ERROR_FAILED, + "Downloading %s failed: %s", + url, errbuf); + return FALSE; + } g_set_error (error, AS_ERROR, AS_ERROR_FAILED, - "Downloading failed: %s", - soup_status_get_phrase (status)); + "Downloading %s failed", + url); return FALSE; } /* save new file */ ret = g_file_set_contents (cache_filename, - msg->response_body->data, - (gssize) msg->response_body->length, + (const gchar *) buf->data, + (gssize) buf->len, error); if (!ret) return FALSE; @@ -4437,6 +4445,11 @@ main (int argc, char *argv[]) priv = g_new0 (AsUtilPrivate, 1); priv->profile = as_profile_new (); + /* networking */ + priv->curl = curl_easy_init(); + (void)curl_easy_setopt(priv->curl, CURLOPT_USERAGENT, "appstream-util"); + (void)curl_easy_setopt(priv->curl, CURLOPT_CONNECTTIMEOUT, 10L); + /* do stuff on ctrl+c */ priv->loop = g_main_loop_new (NULL, FALSE); priv->cancellable = g_cancellable_new (); @@ -4752,6 +4765,8 @@ out: if (priv != NULL) { if (priv->cmd_array != NULL) g_ptr_array_unref (priv->cmd_array); + if (priv->curl != NULL) + curl_easy_cleanup (priv->curl); g_object_unref (priv->profile); g_object_unref (priv->cancellable); g_main_loop_unref (priv->loop); diff --git a/client/meson.build b/client/meson.build index d520508..fd03e62 100644 --- a/client/meson.build +++ b/client/meson.build @@ -10,9 +10,9 @@ if get_option('builder') asbuilder_incdir, ], dependencies : [ - glib, + gio, gdkpixbuf, - soup, + libcurl, libarchive ], link_with : [ @@ -33,9 +33,9 @@ appstream_util = executable( asglib_incdir, ], dependencies : [ - glib, + gio, gdkpixbuf, - soup, + libcurl, libarchive, ], link_with : asglib, @@ -52,9 +52,9 @@ appstream_compose = executable( asglib_incdir, ], dependencies : [ - glib, + gio, gdkpixbuf, - soup, + libcurl, libarchive, ], link_with : asglib, diff --git a/contrib/ci/Dockerfile-fedora b/contrib/ci/Dockerfile-fedora index ba97da5..930765d 100644 --- a/contrib/ci/Dockerfile-fedora +++ b/contrib/ci/Dockerfile-fedora @@ -15,7 +15,7 @@ RUN dnf -y install \ gtk-doc \ json-glib-devel \ libarchive-devel \ - libsoup-devel \ + libcurl-devel \ libstemmer-devel \ libuuid-devel \ libxslt \ diff --git a/contrib/libappstream-glib.spec.in b/contrib/libappstream-glib.spec.in index 0013caa..3c4dd0f 100644 --- a/contrib/libappstream-glib.spec.in +++ b/contrib/libappstream-glib.spec.in @@ -1,5 +1,4 @@ %global glib2_version 2.45.8 -%global libsoup_version 2.51.92 %global json_glib_version 1.1.1 %global gdk_pixbuf_version 2.31.5 %define alphatag #ALPHATAG# @@ -18,7 +17,7 @@ BuildRequires: gtk-doc BuildRequires: gobject-introspection-devel BuildRequires: gperf BuildRequires: libarchive-devel -BuildRequires: libsoup-devel >= %{libsoup_version} +BuildRequires: libcurl-devel BuildRequires: gdk-pixbuf2-devel >= %{gdk_pixbuf_version} BuildRequires: gtk3-devel BuildRequires: gettext @@ -42,7 +41,6 @@ BuildRequires: docbook-style-xsl Requires: gdk-pixbuf2%{?_isa} >= %{gdk_pixbuf_version} Requires: glib2%{?_isa} >= %{glib2_version} Requires: json-glib%{?_isa} >= %{json_glib_version} -Requires: libsoup%{?_isa} >= %{libsoup_version} # no longer required Obsoletes: appdata-tools < 0.1.9 diff --git a/libappstream-builder/meson.build b/libappstream-builder/meson.build index 79e8a74..2c7824c 100644 --- a/libappstream-builder/meson.build +++ b/libappstream-builder/meson.build @@ -6,11 +6,10 @@ asbuilder_cargs = [ ] deps = [ - glib, + gio, gmodule, gdkpixbuf, libarchive, - soup, ] if get_option('dep11') @@ -68,7 +67,7 @@ asb_self_test = executable( include_directories('..'), asglib_incdir, ], - dependencies : [glib, gdkpixbuf, soup], + dependencies : [gio, gdkpixbuf], c_args : cargs + [ '-DTESTDIRSRC="@0@/../data/tests"'.format(meson.current_source_dir()), '-DTESTDIRBUILD="@0@/../data/tests"'.format(meson.current_build_dir()), diff --git a/libappstream-glib/as-app-validate.c b/libappstream-glib/as-app-validate.c index feaa466..0f9130b 100644 --- a/libappstream-glib/as-app-validate.c +++ b/libappstream-glib/as-app-validate.c @@ -8,8 +8,7 @@ #include "config.h" #include -#include -#include +#include #include #include "as-app-private.h" @@ -22,7 +21,7 @@ typedef struct { AsAppValidateFlags flags; GPtrArray *screenshot_urls; GPtrArray *probs; - SoupSession *session; + CURL *curl; gboolean previous_para_was_short; gchar *previous_para_was_short_str; guint para_chars_before_list; @@ -413,15 +412,25 @@ as_app_validate_image_url_already_exists (AsAppValidateHelper *helper, return FALSE; } +static size_t +as_app_validate_download_write_callback_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + GByteArray *buf = (GByteArray *)userdata; + gsize realsize = size * nmemb; + g_byte_array_append(buf, (const guint8 *)ptr, realsize); + return realsize; +} + static gboolean ai_app_validate_image_check (AsImage *im, AsAppValidateHelper *helper) { AsImageAlphaFlags alpha_flags; + CURLcode res; const gchar *url; gboolean require_correct_aspect_ratio = FALSE; gdouble desired_aspect = 1.777777778; gdouble screenshot_aspect; - guint status_code; + gchar errbuf[CURL_ERROR_SIZE] = {'\0'}; guint screenshot_height; guint screenshot_width; guint ss_size_height_max = 900; @@ -429,9 +438,8 @@ ai_app_validate_image_check (AsImage *im, AsAppValidateHelper *helper) guint ss_size_width_max = 1600; guint ss_size_width_min = 624; g_autoptr(GdkPixbuf) pixbuf = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new(); g_autoptr(GInputStream) stream = NULL; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) base_uri = NULL; /* make the requirements more strict */ if ((helper->flags & AS_APP_VALIDATE_FLAG_STRICT) > 0) { @@ -453,37 +461,28 @@ ai_app_validate_image_check (AsImage *im, AsAppValidateHelper *helper) /* GET file */ url = as_image_get_url (im); g_debug ("checking %s", url); - base_uri = soup_uri_new (url); - if (!SOUP_URI_VALID_FOR_HTTP (base_uri)) { + (void)curl_easy_setopt(helper->curl, CURLOPT_URL, url); + (void)curl_easy_setopt(helper->curl, CURLOPT_ERRORBUFFER, errbuf); + (void)curl_easy_setopt(helper->curl, + CURLOPT_WRITEFUNCTION, + as_app_validate_download_write_callback_cb); + (void)curl_easy_setopt(helper->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform(helper->curl); + if (res != CURLE_OK) { + if (errbuf[0] != '\0') { + ai_app_validate_add (helper, + AS_PROBLEM_KIND_URL_NOT_FOUND, + " url not valid [%s]: %s", url, errbuf); + return FALSE; + } ai_app_validate_add (helper, AS_PROBLEM_KIND_URL_NOT_FOUND, - " url not valid [%s]", url); - return FALSE; - } - msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri); - if (msg == NULL) { - g_warning ("Failed to setup message"); - return FALSE; - } - - /* send sync */ - status_code = soup_session_send_message (helper->session, msg); - if (SOUP_STATUS_IS_TRANSPORT_ERROR(status_code)) { - ai_app_validate_add (helper, - AS_PROBLEM_KIND_URL_NOT_FOUND, - " failed to connect: %s [%s]", - soup_status_get_phrase(status_code), url); - return FALSE; - } else if (status_code != SOUP_STATUS_OK) { - ai_app_validate_add (helper, - AS_PROBLEM_KIND_URL_NOT_FOUND, - " failed to download (HTTP %d: %s) [%s]", - status_code, soup_status_get_phrase(status_code), url); + " url not valid [%s]: %s", url, curl_easy_strerror(res)); return FALSE; } /* check if it's a zero sized file */ - if (msg->response_body->length == 0) { + if (buf->len == 0) { ai_app_validate_add (helper, AS_PROBLEM_KIND_FILE_INVALID, " url is a zero length file [%s]", @@ -492,8 +491,8 @@ ai_app_validate_image_check (AsImage *im, AsAppValidateHelper *helper) } /* create a buffer with the data */ - stream = g_memory_input_stream_new_from_data (msg->response_body->data, - (gssize) msg->response_body->length, + stream = g_memory_input_stream_new_from_data (buf->data, + (gssize) buf->len, NULL); if (stream == NULL) { ai_app_validate_add (helper, @@ -993,20 +992,9 @@ as_app_validate_releases (AsApp *app, AsAppValidateHelper *helper, GError **erro static gboolean as_app_validate_setup_networking (AsAppValidateHelper *helper, GError **error) { - helper->session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, - "libappstream-glib", - SOUP_SESSION_TIMEOUT, - 5000, - NULL); - if (helper->session == NULL) { - g_set_error_literal (error, - AS_APP_ERROR, - AS_APP_ERROR_FAILED, - "Failed to set up networking"); - return FALSE; - } - soup_session_add_feature_by_type (helper->session, - SOUP_TYPE_PROXY_RESOLVER_DEFAULT); + helper->curl = curl_easy_init(); + (void)curl_easy_setopt(helper->curl, CURLOPT_USERAGENT, "libappstream-glib"); + (void)curl_easy_setopt(helper->curl, CURLOPT_CONNECTTIMEOUT, 5L); return TRUE; } @@ -1133,8 +1121,8 @@ as_app_validate_helper_free (AsAppValidateHelper *helper) { g_ptr_array_unref (helper->screenshot_urls); g_free (helper->previous_para_was_short_str); - if (helper->session != NULL) - g_object_unref (helper->session); + if (helper->curl != NULL) + curl_easy_cleanup (helper->curl); g_free (helper); } diff --git a/libappstream-glib/as-utils.c b/libappstream-glib/as-utils.c index 007a86b..d9b0f56 100644 --- a/libappstream-glib/as-utils.c +++ b/libappstream-glib/as-utils.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #ifndef _WIN32 #ifdef __APPLE__ diff --git a/libappstream-glib/meson.build b/libappstream-glib/meson.build index 89a007e..886f6c6 100644 --- a/libappstream-glib/meson.build +++ b/libappstream-glib/meson.build @@ -6,9 +6,9 @@ cargs = [ deps = [ gdkpixbuf, - glib, + gio, libarchive, - soup, + libcurl, ] if platform_win32 diff --git a/meson.build b/meson.build index 16ae5a4..c761dad 100644 --- a/meson.build +++ b/meson.build @@ -63,7 +63,7 @@ plugindir = join_paths(get_option('prefix'), 'asb-plugins-' + as_plugin_version) glib_ver = '>= 2.58.0' -glib = dependency('glib-2.0', version : glib_ver) +gio = dependency('gio-2.0', version : glib_ver) gmodule = dependency('gmodule-2.0', version : glib_ver) if platform_win32 giowindows = dependency('gio-windows-2.0', version : glib_ver) @@ -74,7 +74,7 @@ else uuid = dependency('uuid') endif libarchive = dependency('libarchive') -soup = dependency('libsoup-2.4', version : '>= 2.51.92') +libcurl = dependency('libcurl', version : '>= 7.56.0') json_glib = dependency('json-glib-1.0', version : '>= 1.1.2') gdkpixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.31.5') -- cgit v1.2.1