diff --git a/.circleci/config.yml b/.circleci/config.yml index e1aa3c5af..62d640ea0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,14 +32,16 @@ jobs: gcc gcab mingw32-nsis + mingw64-brotli mingw64-gcc mingw64-pkg-config mingw64-glib2 + mingw64-gnutls mingw64-libgusb mingw64-sqlite mingw64-libarchive mingw64-json-glib - mingw64-libsoup + mingw64-curl wine - checkout - run: diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index c3d3023f8..636ef880d 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -11,7 +11,7 @@ license=('GPL2') depends=('libgusb' 'modemmanager' 'tpm2-tss') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' - 'libsoup' 'polkit' 'gcab') + 'curl' 'polkit' 'gcab') pkgver() { cd ${pkgname} diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index d6b812e54..63767e6dd 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -817,20 +817,20 @@ - + - libsoup + curl - libsoup-devel + libcurl-devel - libsoup-devel + libcurl-devel - libsoup2.4-dev:s390x + libcurl4-gnutls-dev:s390x diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index e6c7dcd86..82c6a4c9f 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -1,7 +1,7 @@ %global glib2_version 2.45.8 %global libxmlb_version 0.1.3 %global libgusb_version 0.3.5 -%global libsoup_version 2.51.92 +%global libcurl_version 7.62.0 %global libjcat_version 0.1.0 %global systemd_version 231 %global json_glib_version 1.1.1 @@ -55,7 +55,7 @@ BuildRequires: libxmlb-devel >= %{libxmlb_version} BuildRequires: libgcab1-devel BuildRequires: libgudev1-devel BuildRequires: libgusb-devel >= %{libgusb_version} -BuildRequires: libsoup-devel >= %{libsoup_version} +BuildRequires: libcurl-devel >= %{libcurl_version} BuildRequires: libjcat-devel >= %{libjcat_version} BuildRequires: polkit-devel >= 0.103 BuildRequires: sqlite-devel @@ -112,7 +112,6 @@ Requires(postun): systemd Requires: glib2%{?_isa} >= %{glib2_version} Requires: libxmlb%{?_isa} >= %{libxmlb_version} Requires: libgusb%{?_isa} >= %{libgusb_version} -Requires: libsoup%{?_isa} >= %{libsoup_version} Requires: bubblewrap Requires: shared-mime-info diff --git a/contrib/setup-win32.nsi b/contrib/setup-win32.nsi index 83836a45f..ac3865385 100644 --- a/contrib/setup-win32.nsi +++ b/contrib/setup-win32.nsi @@ -48,7 +48,7 @@ Section "fwupd" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libnettle-7.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libp11-kit-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libpcre-1.dll" - File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libsoup-2.4-1.dll" + File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libcurl-4.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libsqlite3-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libtasn1-6.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libusb-1.0.dll" diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 30672383a..418532a58 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -8,7 +8,7 @@ #include #include -#include +#include #ifdef HAVE_GIO_UNIX #include #endif @@ -52,10 +52,14 @@ typedef struct { gchar *host_security_id; GDBusConnection *conn; GDBusProxy *proxy; - SoupSession *soup_session; gchar *user_agent; } FwupdClientPrivate; +typedef struct { + CURL *curl; + curl_mime *mime; +} FwupdCurlHelper; + enum { SIGNAL_CHANGED, SIGNAL_STATUS_CHANGED, @@ -71,7 +75,7 @@ enum { PROP_PERCENTAGE, PROP_DAEMON_VERSION, PROP_TAINTED, - PROP_SOUP_SESSION, + PROP_SOUP_SESSION, /* unused ABI */ PROP_HOST_PRODUCT, PROP_HOST_MACHINE_ID, PROP_HOST_SECURITY_ID, @@ -84,6 +88,20 @@ static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (FwupdClient, fwupd_client, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_client_get_instance_private (o)) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) + +static void +fwupd_client_curl_helper_free (FwupdCurlHelper *helper) +{ + if (helper->curl != NULL) + curl_easy_cleanup (helper->curl); + if (helper->mime != NULL) + curl_mime_free (helper->mime); + g_free (helper); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdCurlHelper, fwupd_client_curl_helper_free) + static void fwupd_client_set_host_product (FwupdClient *self, const gchar *host_product) { @@ -262,12 +280,6 @@ gboolean fwupd_client_ensure_networking (FwupdClient *self, GError **error) { FwupdClientPrivate *priv = GET_PRIVATE (self); - const gchar *http_proxy; - g_autoptr(SoupSession) session = NULL; - - /* already exists */ - if (priv->soup_session != NULL) - return TRUE; /* check the user agent is sane */ if (priv->user_agent == NULL) { @@ -284,22 +296,62 @@ fwupd_client_ensure_networking (FwupdClient *self, GError **error) "user agent unsuitable; fwupd version required"); return FALSE; } + return TRUE; +} - /* create the soup session */ - session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, priv->user_agent, - SOUP_SESSION_TIMEOUT, 60, - NULL); - if (session == NULL) { +static int +fwupd_client_progress_callback_cb (void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + FwupdClient *self = FWUPD_CLIENT (clientp); + + /* calculate percentage */ + if (dltotal > 0 && dlnow >= 0 && dlnow <= dltotal) { + guint percentage = (guint) ((100 * dlnow) / dltotal); + g_debug ("download progress: %u%%", percentage); + fwupd_client_set_percentage (self, percentage); + } else if (ultotal > 0 && ulnow >= 0 && ulnow <= ultotal) { + guint percentage = (guint) ((100 * ulnow) / ultotal); + g_debug ("upload progress: %u%%", percentage); + fwupd_client_set_percentage (self, percentage); + } + + return 0; +} + +static FwupdCurlHelper * +fwupd_client_curl_new (FwupdClient *self, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + const gchar *http_proxy; + g_autoptr(FwupdCurlHelper) helper = g_new0 (FwupdCurlHelper, 1); + + /* check the user agent is sane */ + if (!fwupd_client_ensure_networking (self, error)) + return NULL; + + /* create the session */ + helper->curl = curl_easy_init (); + if (helper->curl == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to setup networking"); - return FALSE; + return NULL; } + if (g_getenv ("FWUPD_CURL_VERBOSE") != NULL) + curl_easy_setopt (helper->curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (helper->curl, CURLOPT_XFERINFOFUNCTION, fwupd_client_progress_callback_cb); + curl_easy_setopt (helper->curl, CURLOPT_XFERINFODATA, self); + curl_easy_setopt (helper->curl, CURLOPT_USERAGENT, priv->user_agent); + curl_easy_setopt (helper->curl, CURLOPT_CONNECTTIMEOUT, 60L); /* relax the SSL checks for broken corporate proxies */ if (g_getenv ("DISABLE_SSL_STRICT") != NULL) - g_object_set (session, SOUP_SESSION_SSL_STRICT, FALSE, NULL); + curl_easy_setopt (helper->curl, CURLOPT_SSL_VERIFYPEER, 0L); /* set the proxy */ http_proxy = g_getenv ("https_proxy"); @@ -309,22 +361,12 @@ fwupd_client_ensure_networking (FwupdClient *self, GError **error) http_proxy = g_getenv ("http_proxy"); if (http_proxy == NULL) http_proxy = g_getenv ("HTTP_PROXY"); - if (http_proxy != NULL && strlen (http_proxy) > 0) { - g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); - if (proxy_uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid proxy URI: %s", http_proxy); - return FALSE; - } - g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); - } + if (http_proxy != NULL && strlen (http_proxy) > 0) + curl_easy_setopt (helper->curl, CURLOPT_PROXY, http_proxy); /* this disables the double-compression of the firmware.xml.gz file */ - soup_session_remove_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); - priv->soup_session = g_steal_pointer (&session); - return TRUE; + curl_easy_setopt (helper->curl, CURLOPT_HTTP_CONTENT_DECODING, 0L); + return g_steal_pointer (&helper); } static void @@ -2234,6 +2276,13 @@ fwupd_client_install_release_download_cb (GObject *source, GAsyncResult *res, gp g_steal_pointer (&task)); } +static gboolean +fwupd_client_is_url (const gchar *perhaps_url) +{ + g_autoptr(CURLU) h = curl_url (); + return curl_url_set (h, CURLUPART_URL, perhaps_url, 0) == CURLUE_OK; +} + static void fwupd_client_install_release_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data) { @@ -2242,7 +2291,6 @@ fwupd_client_install_release_remote_cb (GObject *source, GAsyncResult *res, gpoi g_autoptr(FwupdRemote) remote = NULL; g_autoptr(GError) error = NULL; g_autoptr(GTask) task = G_TASK (user_data); - g_autoptr(SoupURI) uri = NULL; FwupdClientInstallReleaseData *data = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); @@ -2254,8 +2302,8 @@ fwupd_client_install_release_remote_cb (GObject *source, GAsyncResult *res, gpoi } /* local and directory remotes may have the firmware already */ - uri = soup_uri_new (fwupd_release_get_uri (data->release)); - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && uri == NULL) { + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && + !fwupd_client_is_url (fwupd_release_get_uri (data->release))) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); fn = g_build_filename (path, fwupd_release_get_uri (data->release), NULL); @@ -3929,97 +3977,60 @@ fwupd_client_set_user_agent_for_package (FwupdClient *self, priv->user_agent = g_string_free (str, FALSE); } -static void -fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data) +static size_t +fwupd_client_download_write_callback_cb (char *ptr, size_t size, size_t nmemb, void *userdata) { - guint percentage; - goffset header_size; - goffset body_length; - FwupdClient *self = FWUPD_CLIENT (user_data); - - /* if it's returning "Found" or an error, ignore the percentage */ - if (msg->status_code != SOUP_STATUS_OK) { - g_debug ("ignoring status code %u (%s)", - msg->status_code, msg->reason_phrase); - return; - } - - /* get data */ - body_length = msg->response_body->length; - header_size = soup_message_headers_get_content_length (msg->response_headers); - if (header_size < body_length) - return; - - /* calculate percentage */ - percentage = (guint) ((100 * body_length) / header_size); - g_debug ("progress: %u%%", percentage); - fwupd_client_set_percentage (self, percentage); + GByteArray *buf = (GByteArray *) userdata; + gsize realsize = size * nmemb; + g_byte_array_append (buf, (const guint8 *) ptr, realsize); + return realsize; } static void -fwupd_client_read_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +fwupd_client_download_bytes_thread_cb (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { - g_autoptr(GBytes) bytes = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GTask) task = G_TASK (user_data); + FwupdClient *self = FWUPD_CLIENT (source_object); + FwupdCurlHelper *helper = g_task_get_task_data (task); + CURLcode res; + gchar errbuf[CURL_ERROR_SIZE] = { '\0' }; + g_autoptr(GByteArray) buf = g_byte_array_new (); - bytes = fwupd_input_stream_read_bytes_finish (G_INPUT_STREAM (source), res, &error); - if (bytes == NULL) { - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - - /* success */ - g_task_return_pointer (task, - g_steal_pointer (&bytes), - (GDestroyNotify) g_bytes_unref); -} - -static void -fwupd_client_download_bytes_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) -{ - g_autoptr(GTask) task = G_TASK (user_data); - FwupdClient *self = g_task_get_source_object (task); - FwupdClientPrivate *priv = GET_PRIVATE (self); - GCancellable *cancellable = g_task_get_cancellable (task); - g_autoptr(GError) error = NULL; - g_autoptr(GInputStream) istr = NULL; - guint status_code = 0; - SoupMessage *msg = g_task_get_task_data (task); - - /* get the result */ + curl_easy_setopt (helper->curl, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt (helper->curl, CURLOPT_WRITEFUNCTION, fwupd_client_download_write_callback_cb); + curl_easy_setopt (helper->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform (helper->curl); fwupd_client_set_status (self, FWUPD_STATUS_IDLE); - istr = soup_session_send_finish (priv->soup_session, res, &error); - if (istr == NULL) { - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - - /* check the input stream before reading the data */ - g_object_get (msg, "status-code", &status_code, NULL); - g_debug ("status-code was %u", status_code); - if (status_code == 429) { + if (res != CURLE_OK) { + glong status_code = 0; + curl_easy_getinfo (helper->curl, CURLINFO_RESPONSE_CODE, &status_code); + g_debug ("status-code was %ld", status_code); + if (status_code == 429) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download due to server limit"); + return; + } + if (errbuf[0] != '\0') { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "%s", errbuf); + return; + } g_task_return_new_error (task, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to download due to server limit"); - return; - } - if (status_code != SOUP_STATUS_OK) { - g_task_return_new_error (task, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download: %s", - soup_status_get_phrase (status_code)); - return; - } + "%s", curl_easy_strerror (res)); - /* read the input stream into a GBytes, async */ - fwupd_input_stream_read_bytes_async (istr, cancellable, - fwupd_client_read_bytes_cb, - g_steal_pointer (&task)); + return; + } + g_task_return_pointer (task, + g_byte_array_free_to_bytes (g_steal_pointer (&buf)), + (GDestroyNotify) g_bytes_unref); } /** @@ -4049,9 +4060,8 @@ fwupd_client_download_bytes_async (FwupdClient *self, { FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GTask) task = NULL; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; g_autoptr(GError) error = NULL; + g_autoptr(FwupdCurlHelper) helper = NULL; g_return_if_fail (FWUPD_IS_CLIENT (self)); g_return_if_fail (url != NULL); @@ -4060,31 +4070,18 @@ fwupd_client_download_bytes_async (FwupdClient *self, /* ensure networking set up */ task = g_task_new (self, cancellable, callback, callback_data); - if (!fwupd_client_ensure_networking (self, &error)) { + helper = fwupd_client_curl_new (self, &error); + if (helper == NULL) { g_task_return_error (task, g_steal_pointer (&error)); return; } + curl_easy_setopt (helper->curl, CURLOPT_URL, url); + g_task_set_task_data (task, g_steal_pointer (&helper), (GDestroyNotify) fwupd_client_curl_helper_free); /* download data */ g_debug ("downloading %s", url); - uri = soup_uri_new (url); - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); - if (msg == NULL) { - g_task_return_new_error (task, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", url); - return; - } - g_signal_connect (msg, "got-chunk", - G_CALLBACK (fwupd_client_download_chunk_cb), - self); - g_task_set_task_data (task, g_object_ref (msg), (GDestroyNotify) g_object_unref); fwupd_client_set_status (self, FWUPD_STATUS_DOWNLOADING); - soup_session_send_async (priv->soup_session, msg, - cancellable, - fwupd_client_download_bytes_cb, - g_steal_pointer (&task)); + g_task_run_in_thread (task, fwupd_client_download_bytes_thread_cb); } /** @@ -4109,42 +4106,43 @@ fwupd_client_download_bytes_finish (FwupdClient *self, GAsyncResult *res, GError } static void -fwupd_client_upload_bytes_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) +fwupd_client_upload_bytes_thread_cb (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { - g_autoptr(GTask) task = G_TASK (user_data); - FwupdClient *self = g_task_get_source_object (task); - FwupdClientPrivate *priv = GET_PRIVATE (self); - GCancellable *cancellable = g_task_get_cancellable (task); - g_autoptr(GError) error = NULL; - g_autoptr(GInputStream) istr = NULL; - guint status_code; - SoupMessage *msg = g_task_get_task_data (task); + FwupdClient *self = FWUPD_CLIENT (source_object); + FwupdCurlHelper *helper = g_task_get_task_data (task); + CURLcode res; + gchar errbuf[CURL_ERROR_SIZE] = { '\0' }; + g_autoptr(GByteArray) buf = g_byte_array_new (); - /* get the result */ - istr = soup_session_send_finish (priv->soup_session, res, &error); - if (istr == NULL) { - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - - /* check the input stream before reading the data */ - g_object_get (msg, "status-code", &status_code, NULL); - g_debug ("status-code was %u", status_code); - if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { + curl_easy_setopt (helper->curl, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt (helper->curl, CURLOPT_WRITEFUNCTION, fwupd_client_download_write_callback_cb); + curl_easy_setopt (helper->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform (helper->curl); + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); + if (res != CURLE_OK) { + glong status_code = 0; + curl_easy_getinfo (helper->curl, CURLINFO_RESPONSE_CODE, &status_code); + g_debug ("status-code was %ld", status_code); + if (errbuf[0] != '\0') { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "%s", errbuf); + return; + } g_task_return_new_error (task, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to download: %s", - soup_status_get_phrase (status_code)); + "%s", curl_easy_strerror (res)); + return; } - - /* read the input stream into a GBytes, async */ - fwupd_input_stream_read_bytes_async (istr, cancellable, - fwupd_client_read_bytes_cb, - g_steal_pointer (&task)); + g_task_return_pointer (task, + g_byte_array_free_to_bytes (g_steal_pointer (&buf)), + (GDestroyNotify) g_bytes_unref); } /** @@ -4178,8 +4176,7 @@ fwupd_client_upload_bytes_async (FwupdClient *self, { FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GTask) task = NULL; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; + g_autoptr(FwupdCurlHelper) helper = NULL; g_autoptr(GError) error = NULL; g_return_if_fail (FWUPD_IS_CLIENT (self)); @@ -4189,48 +4186,37 @@ fwupd_client_upload_bytes_async (FwupdClient *self, /* ensure networking set up */ task = g_task_new (self, cancellable, callback, callback_data); - if (!fwupd_client_ensure_networking (self, &error)) { + helper = fwupd_client_curl_new (self, &error); + if (helper == NULL) { g_task_return_error (task, g_steal_pointer (&error)); return; } - /* download data */ - g_debug ("downloading %s", url); - uri = soup_uri_new (url); - /* build message */ if ((flags & FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || signature != NULL) { - g_autoptr(SoupMultipart) mp = NULL; - mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - soup_multipart_append_form_string (mp, "payload", payload); - if (signature != NULL) - soup_multipart_append_form_string (mp, "signature", signature); - msg = soup_form_request_new_from_multipart (url, mp); + curl_mimepart *part; + helper->mime = curl_mime_init (helper->curl); + curl_easy_setopt (helper->curl, CURLOPT_MIMEPOST, helper->mime); + part = curl_mime_addpart (helper->mime); + curl_mime_data (part, payload, CURL_ZERO_TERMINATED); + curl_mime_name (part, "payload"); + if (signature != NULL) { + part = curl_mime_addpart (helper->mime); + curl_mime_data (part, signature, CURL_ZERO_TERMINATED); + curl_mime_name (part, "signature"); + } } else { - msg = soup_message_new (SOUP_METHOD_POST, url); - soup_message_set_request (msg, "application/json; charset=utf-8", - SOUP_MEMORY_COPY, payload, strlen (payload)); + curl_easy_setopt (helper->mime, CURLOPT_POST, 1L); + curl_easy_setopt (helper->curl, CURLOPT_POSTFIELDSIZE, strlen (payload)); + curl_easy_setopt (helper->curl, CURLOPT_COPYPOSTFIELDS, payload); } - /* POST request */ - if (msg == NULL) { - g_task_return_new_error (task, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", url); - return; - } - g_signal_connect (msg, "got-chunk", - G_CALLBACK (fwupd_client_download_chunk_cb), - self); - g_task_set_task_data (task, g_object_ref (msg), (GDestroyNotify) g_object_unref); fwupd_client_set_status (self, FWUPD_STATUS_IDLE); g_debug ("uploading to %s", url); - soup_session_send_async (priv->soup_session, msg, - cancellable, - fwupd_client_upload_bytes_cb, - g_steal_pointer (&task)); + curl_easy_setopt (helper->curl, CURLOPT_URL, url); + g_task_set_task_data (task, g_steal_pointer (&helper), (GDestroyNotify) fwupd_client_curl_helper_free); + g_task_run_in_thread (task, fwupd_client_upload_bytes_thread_cb); } /** @@ -4269,7 +4255,7 @@ fwupd_client_get_property (GObject *object, guint prop_id, g_value_set_boolean (value, priv->tainted); break; case PROP_SOUP_SESSION: - g_value_set_object (value, priv->soup_session); + g_value_set_object (value, NULL); break; case PROP_PERCENTAGE: g_value_set_uint (value, priv->percentage); @@ -4309,9 +4295,6 @@ fwupd_client_set_property (GObject *object, guint prop_id, case PROP_PERCENTAGE: priv->percentage = g_value_get_uint (value); break; - case PROP_SOUP_SESSION: - g_set_object (&priv->soup_session, g_value_get_object (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -4471,12 +4454,12 @@ fwupd_client_class_init (FwupdClientClass *klass) /** * FwupdClient:soup-session: * - * The libsoup session. + * The libsoup session, now unused. * * Since: 1.4.5 */ - pspec = g_param_spec_object ("soup-session", NULL, NULL, SOUP_TYPE_SESSION, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME); + pspec = g_param_spec_object ("soup-session", NULL, NULL, G_TYPE_OBJECT, + G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_SOUP_SESSION, pspec); /** @@ -4533,8 +4516,6 @@ fwupd_client_finalize (GObject *object) g_object_unref (priv->conn); if (priv->proxy != NULL) g_object_unref (priv->proxy); - if (priv->soup_session != NULL) - g_object_unref (priv->soup_session); G_OBJECT_CLASS (fwupd_client_parent_class)->finalize (object); } diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index f63a2668d..7122b5400 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -6,7 +6,7 @@ #include "config.h" -#include +#include #include #include "fwupd-deprecated.h" @@ -67,6 +67,10 @@ enum { G_DEFINE_TYPE_WITH_PRIVATE (FwupdRemote, fwupd_remote, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_remote_get_instance_private (o)) +typedef gchar curlptr; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curlptr, curl_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) + static void fwupd_remote_set_username (FwupdRemote *self, const gchar *username) { @@ -150,11 +154,11 @@ fwupd_remote_set_filename_source (FwupdRemote *self, const gchar *filename_sourc priv->filename_source = g_strdup (filename_source); } -static SoupURI * +static CURLU * fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) { FwupdRemotePrivate *priv = GET_PRIVATE (self); - SoupURI *uri; + g_autoptr(CURLU) uri = curl_url (); g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); g_return_val_if_fail (url != NULL, NULL); @@ -162,48 +166,43 @@ fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) /* create URI, substituting if required */ if (priv->firmware_base_uri != NULL) { - g_autoptr(SoupURI) uri_tmp = NULL; g_autofree gchar *basename = NULL; - g_autofree gchar *url2 = NULL; - uri_tmp = soup_uri_new (url); - if (uri_tmp == NULL) { + g_autofree gchar *path_new = NULL; + g_autoptr(curlptr) path = NULL; + g_autoptr(CURLU) uri_tmp = curl_url (); + if (curl_url_set (uri_tmp, CURLUPART_URL, url, 0) != CURLUE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI '%s'", url); - return NULL; - } - basename = g_path_get_basename (soup_uri_get_path (uri_tmp)); - url2 = g_build_filename (priv->firmware_base_uri, basename, NULL); - uri = soup_uri_new (url2); - if (uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI '%s'", url2); + "Failed to parse url '%s'", url); return NULL; } + curl_url_get (uri_tmp, CURLUPART_PATH, &path, 0); + basename = g_path_get_basename (path); + path_new = g_build_filename (priv->firmware_base_uri, basename, NULL); + curl_url_set (uri, CURLUPART_URL, path_new, 0); /* use the base URI of the metadata to build the full path */ } else if (g_strstr_len (url, -1, "/") == NULL) { g_autofree gchar *basename = NULL; - g_autofree gchar *path = NULL; - uri = soup_uri_new (priv->metadata_uri); - if (uri == NULL) { + g_autofree gchar *path_new = NULL; + g_autoptr(curlptr) path = NULL; + if (curl_url_set (uri, CURLUPART_URL, priv->metadata_uri, 0) != CURLUE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to parse metadata URI '%s'", url); + "Failed to parse url '%s'", + priv->metadata_uri); return NULL; } - basename = g_path_get_dirname (soup_uri_get_path (uri)); - path = g_build_filename (basename, url, NULL); - soup_uri_set_path (uri, path); + curl_url_get (uri, CURLUPART_PATH, &path, 0); + basename = g_path_get_dirname (path); + path_new = g_build_filename (basename, url, NULL); + curl_url_set (uri, CURLUPART_URL, path_new, 0); /* a normal URI */ } else { - uri = soup_uri_new (url); - if (uri == NULL) { + if (curl_url_set (uri, CURLUPART_URL, url, 0) != CURLUE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -214,10 +213,10 @@ fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) /* set the username and password */ if (priv->username != NULL) - soup_uri_set_user (uri, priv->username); + curl_url_set (uri, CURLUPART_USER, priv->username, 0); if (priv->password != NULL) - soup_uri_set_password (uri, priv->password); - return uri; + curl_url_set (uri, CURLUPART_PASSWORD, priv->password, 0); + return g_steal_pointer (&uri); } /* note, this has to be set before username and password */ @@ -225,12 +224,6 @@ static void fwupd_remote_set_metadata_uri (FwupdRemote *self, const gchar *metadata_uri) { FwupdRemotePrivate *priv = GET_PRIVATE (self); - g_autoptr(SoupURI) uri = NULL; - - /* build the URI */ - uri = soup_uri_new (metadata_uri); - if (uri == NULL) - return; /* save this so we can export the object as a GVariant */ priv->metadata_uri = g_strdup (metadata_uri); @@ -872,10 +865,12 @@ fwupd_remote_get_checksum (FwupdRemote *self) gchar * fwupd_remote_build_firmware_uri (FwupdRemote *self, const gchar *url, GError **error) { - g_autoptr(SoupURI) uri = fwupd_remote_build_uri (self, url, error); + g_autoptr(curlptr) tmp = NULL; + g_autoptr(CURLU) uri = fwupd_remote_build_uri (self, url, error); if (uri == NULL) return NULL; - return soup_uri_to_string (uri, FALSE); + curl_url_get (uri, CURLUPART_URL, &tmp, 0); + return g_strdup (tmp); } /** diff --git a/libfwupd/meson.build b/libfwupd/meson.build index f31581497..a303a8d63 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -32,7 +32,7 @@ install_headers([ libfwupd_deps = [ giounix, - soup, + libcurl, libjcat, libjsonglib, ] @@ -122,19 +122,18 @@ if get_option('introspection') header : 'fwupd.h', dependencies : [ giounix, - soup, + libcurl, ], includes : [ 'Gio-2.0', 'GObject-2.0', - 'Soup-2.4', ], install : true ) gnome.generate_vapi('fwupd', sources : fwupd_gir[0], - packages : ['gio-2.0', 'libsoup-2.4'], + packages : ['gio-2.0'], install : true, ) @@ -178,7 +177,7 @@ if get_option('tests') ], dependencies : [ gio, - soup, + libcurl, libjsonglib, ], link_with : fwupd, diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build index ba8e6bc4d..43517d227 100644 --- a/libfwupdplugin/meson.build +++ b/libfwupdplugin/meson.build @@ -143,7 +143,6 @@ fwupdplugin_pkgg.generate( 'json-glib-1.0', 'libarchive', 'libgcab-1.0', - 'libsoup-2.4', 'xmlb', 'jcat', ], diff --git a/meson.build b/meson.build index 69b526528..5fc77a284 100644 --- a/meson.build +++ b/meson.build @@ -208,7 +208,7 @@ endif libjcat = dependency('jcat', version : '>= 0.1.0', fallback : ['libjcat', 'libjcat_dep']) libjsonglib = dependency('json-glib-1.0', version : '>= 1.1.1') valgrind = dependency('valgrind', required: false) -soup = dependency('libsoup-2.4', version : '>= 2.51.92') +libcurl = dependency('libcurl', version : '>= 7.62.0') if build_daemon if get_option('polkit') polkit = dependency('polkit-gobject-1', version : '>= 0.103') @@ -448,7 +448,6 @@ if build_standalone plugin_deps += giounix plugin_deps += gmodule plugin_deps += gusb - plugin_deps += soup plugin_deps += libarchive plugin_deps += gudev plugin_deps += libjsonglib diff --git a/plugins/redfish/fu-redfish-client.c b/plugins/redfish/fu-redfish-client.c index 9b708f975..6d770932a 100644 --- a/plugins/redfish/fu-redfish-client.c +++ b/plugins/redfish/fu-redfish-client.c @@ -7,7 +7,7 @@ #include "config.h" #include -#include +#include #include #include "fwupd-error.h" @@ -22,14 +22,11 @@ struct _FuRedfishClient { GObject parent_instance; - SoupSession *session; + CURL *curl; gchar *hostname; guint port; - gchar *username; - gchar *password; gchar *update_uri_path; gchar *push_uri_path; - gboolean auth_created; gboolean use_https; gboolean cacheck; GPtrArray *devices; @@ -37,62 +34,57 @@ struct _FuRedfishClient G_DEFINE_TYPE (FuRedfishClient, fu_redfish_client, G_TYPE_OBJECT) -static void -fu_redfish_client_set_auth (FuRedfishClient *self, SoupURI *uri, - SoupMessage *msg) +typedef gchar curlptr; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curlptr, curl_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) + +static size_t +fu_redfish_client_fetch_data_cb (char *ptr, size_t size, size_t nmemb, void *userdata) { - if ((self->username != NULL && self->password != NULL) && - self->auth_created == FALSE) { - /* - * Some redfish implementations miss WWW-Authenticate - * header for a 401 response, and SoupAuthManager couldn't - * generate SoupAuth accordingly. Since DSP0266 makes - * Basic Authorization a requirement for redfish, it shall be - * safe to use Basic Auth for all redfish implementations. - */ - SoupAuthManager *manager = SOUP_AUTH_MANAGER (soup_session_get_feature (self->session, SOUP_TYPE_AUTH_MANAGER)); - g_autoptr(SoupAuth) auth = soup_auth_new (SOUP_TYPE_AUTH_BASIC, - msg, "Basic"); - soup_auth_authenticate (auth, self->username, self->password); - soup_auth_manager_use_auth (manager, uri, auth); - self->auth_created = TRUE; - } + GByteArray *buf = (GByteArray *) userdata; + gsize realsize = size * nmemb; + g_byte_array_append (buf, (const guint8 *) ptr, realsize); + return realsize; } static GBytes * fu_redfish_client_fetch_data (FuRedfishClient *self, const gchar *uri_path, GError **error) { - guint status_code; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; + CURLcode res; + g_autofree gchar *port = g_strdup_printf ("%u", self->port); + g_autoptr(CURLU) uri = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new (); /* create URI */ - uri = soup_uri_new (NULL); - soup_uri_set_scheme (uri, self->use_https ? "https" : "http"); - soup_uri_set_path (uri, uri_path); - soup_uri_set_host (uri, self->hostname); - soup_uri_set_port (uri, self->port); - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); - if (msg == NULL) { - g_autofree gchar *tmp = soup_uri_to_string (uri, FALSE); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to create message for URI %s", tmp); + uri = curl_url (); + curl_url_set (uri, CURLU_DEFAULT_SCHEME, self->use_https ? "https" : "http", 0); + curl_url_set (uri, CURLUPART_PATH, uri_path, 0); + curl_url_set (uri, CURLUPART_HOST, self->hostname, 0); + curl_url_set (uri, CURLUPART_PORT, port, 0); + if (curl_easy_setopt (self->curl, CURLOPT_CURLU, uri) != CURLE_OK) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI"); return NULL; } - fu_redfish_client_set_auth (self, uri, msg); - status_code = soup_session_send_message (self->session, msg); - if (status_code != SOUP_STATUS_OK) { - g_autofree gchar *tmp = soup_uri_to_string (uri, FALSE); + curl_easy_setopt (self->curl, CURLOPT_WRITEFUNCTION, fu_redfish_client_fetch_data_cb); + curl_easy_setopt (self->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform (self->curl); + if (res != CURLE_OK) { + glong status_code = 0; + g_autoptr(curlptr) uri_str = NULL; + curl_easy_getinfo (self->curl, CURLINFO_RESPONSE_CODE, &status_code); + curl_url_get (uri, CURLUPART_URL, &uri_str, 0); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to download %s: %s", - tmp, soup_status_get_phrase (status_code)); + uri_str, curl_easy_strerror (res)); return NULL; } - return g_bytes_new (msg->response_body->data, msg->response_body->length); + + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); } static gboolean @@ -569,19 +561,19 @@ fu_redfish_client_set_smbios_interfaces (FuRedfishClient *self, return TRUE; } +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curl_mime, curl_mime_free) + gboolean fu_redfish_client_update (FuRedfishClient *self, FuDevice *device, GBytes *blob_fw, GError **error) { + CURLcode res; FwupdRelease *release; + curl_mimepart *part; g_autofree gchar *filename = NULL; - - guint status_code; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; - g_autoptr(SoupMultipart) multipart = NULL; - g_autoptr(SoupBuffer) buffer = NULL; - g_autofree gchar *uri_str = NULL; + g_autofree gchar *port = g_strdup_printf ("%u", self->port); + g_autoptr(CURLU) uri = curl_url (); + g_autoptr(curl_mime) mime = curl_mime_init (self->curl); /* Get the update version */ release = fwupd_device_get_release_default (FWUPD_DEVICE (device)); @@ -595,38 +587,35 @@ fu_redfish_client_update (FuRedfishClient *self, FuDevice *device, GBytes *blob_ } /* create URI */ - uri = soup_uri_new (NULL); - soup_uri_set_scheme (uri, self->use_https ? "https" : "http"); - soup_uri_set_path (uri, self->push_uri_path); - soup_uri_set_host (uri, self->hostname); - soup_uri_set_port (uri, self->port); - uri_str = soup_uri_to_string (uri, FALSE); - - /* Create the multipart request */ - multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - buffer = soup_buffer_new (SOUP_MEMORY_COPY, - g_bytes_get_data (blob_fw, NULL), - g_bytes_get_size (blob_fw)); - soup_multipart_append_form_file (multipart, filename, filename, - "application/octet-stream", - buffer); - msg = soup_form_request_new_from_multipart (uri_str, multipart); - if (msg == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to create message for URI %s", uri_str); + curl_url_set (uri, CURLU_DEFAULT_SCHEME, self->use_https ? "https" : "http", 0); + curl_url_set (uri, CURLUPART_PATH, self->push_uri_path, 0); + curl_url_set (uri, CURLUPART_HOST, self->hostname, 0); + curl_url_set (uri, CURLUPART_PORT, port, 0); + if (curl_easy_setopt (self->curl, CURLOPT_CURLU, uri) != CURLE_OK) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI"); return FALSE; } - fu_redfish_client_set_auth (self, uri, msg); - status_code = soup_session_send_message (self->session, msg); - if (status_code != SOUP_STATUS_OK) { + + /* Create the multipart request */ + curl_easy_setopt (self->curl, CURLOPT_MIMEPOST, mime); + part = curl_mime_addpart (mime); + curl_mime_data (part, g_bytes_get_data (blob_fw, NULL), g_bytes_get_size (blob_fw)); + curl_mime_type (part, "application/octet-stream"); + res = curl_easy_perform (self->curl); + if (res != CURLE_OK) { + glong status_code = 0; + g_autoptr(curlptr) uri_str = NULL; + curl_easy_getinfo (self->curl, CURLINFO_RESPONSE_CODE, &status_code); + curl_url_get (uri, CURLUPART_URL, &uri_str, 0); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to upload %s to %s: %s", filename, uri_str, - soup_status_get_phrase (status_code)); + curl_easy_strerror (res)); return FALSE; } @@ -662,24 +651,12 @@ fu_redfish_client_setup (FuRedfishClient *self, GBytes *smbios_table, GError **e return FALSE; } - /* create the soup session */ + /* setup networking */ user_agent = g_strdup_printf ("%s/%s", PACKAGE_NAME, PACKAGE_VERSION); - self->session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, - SOUP_SESSION_TIMEOUT, 60, - NULL); - if (self->session == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to setup networking"); - return FALSE; - } - - if (self->cacheck == FALSE) { - g_object_set (G_OBJECT (self->session), - SOUP_SESSION_SSL_STRICT, FALSE, - NULL); - } + curl_easy_setopt (self->curl, CURLOPT_USERAGENT , user_agent); + curl_easy_setopt (self->curl, CURLOPT_CONNECTTIMEOUT, 60L); + if (self->cacheck == FALSE) + curl_easy_setopt (self->curl, CURLOPT_SSL_VERIFYPEER , 0L); /* this is optional */ if (smbios_table != NULL) { @@ -700,10 +677,6 @@ fu_redfish_client_setup (FuRedfishClient *self, GBytes *smbios_table, GError **e g_debug ("Hostname: %s", self->hostname); if (self->port != 0) g_debug ("Port: %u", self->port); - if (self->username != NULL) - g_debug ("Username: %s", self->username); - if (self->password != NULL) - g_debug ("Password: %s", self->password); /* try to connect */ blob = fu_redfish_client_fetch_data (self, "/redfish/v1/", error); @@ -800,28 +773,24 @@ fu_redfish_client_set_cacheck (FuRedfishClient *self, gboolean cacheck) void fu_redfish_client_set_username (FuRedfishClient *self, const gchar *username) { - g_free (self->username); - self->username = g_strdup (username); + curl_easy_setopt (self->curl, CURLOPT_USERNAME, username); } void fu_redfish_client_set_password (FuRedfishClient *self, const gchar *password) { - g_free (self->password); - self->password = g_strdup (password); + curl_easy_setopt (self->curl, CURLOPT_PASSWORD, password); } static void fu_redfish_client_finalize (GObject *object) { FuRedfishClient *self = FU_REDFISH_CLIENT (object); - if (self->session != NULL) - g_object_unref (self->session); + if (self->curl != NULL) + curl_easy_cleanup (self->curl); g_free (self->update_uri_path); g_free (self->push_uri_path); g_free (self->hostname); - g_free (self->username); - g_free (self->password); g_ptr_array_unref (self->devices); G_OBJECT_CLASS (fu_redfish_client_parent_class)->finalize (object); } @@ -837,6 +806,11 @@ static void fu_redfish_client_init (FuRedfishClient *self) { self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + self->curl = curl_easy_init (); + + /* since DSP0266 makes Basic Authorization a requirement, + * it is safe to use Basic Auth for all implementations */ + curl_easy_setopt (self->curl, CURLOPT_HTTPAUTH, (glong) CURLAUTH_BASIC); } FuRedfishClient * diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index 927627918..205d1394c 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -21,6 +21,7 @@ shared_module('fu_plugin_redfish', c_args : cargs, dependencies : [ plugin_deps, + libcurl, libjsonglib, ], ) @@ -45,6 +46,7 @@ if get_option('tests') ], dependencies : [ plugin_deps, + libcurl, libjsonglib, ], link_with : [ diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 65205bba9..a42ec3ffa 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -35,6 +35,8 @@ apps: command: fwupdagent.wrapper parts: + curl: + source: https://curl.se/download/curl-7.73.0.tar.bz2 tpm2-tss: plugin: autotools source: https://github.com/tpm2-software/tpm2-tss/releases/download/2.3.0/tpm2-tss-2.3.0.tar.gz @@ -211,7 +213,6 @@ parts: - libpci-dev - libpolkit-gobject-1-dev - libsmbios-dev - - libsoup2.4-dev - libsqlite3-dev - libsystemd-dev - locales @@ -232,7 +233,6 @@ parts: - libjson-glib-1.0-0 - libpolkit-gobject-1-0 - libsmbios-c2 - - libsoup2.4-1 - glib-networking - libglib2.0-bin prime: @@ -272,7 +272,7 @@ parts: - -usr/lib/*/pkgconfig # we don't want system gnutls leaking in - -usr/lib/*/libgnutls* - after: [meson, build-introspection, modemmanager, libmbim, libqmi, tpm2-tss, gnutls] + after: [meson, build-introspection, modemmanager, libmbim, libqmi, tpm2-tss, gnutls, curl] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff --git a/src/fu-tool.c b/src/fu-tool.c index f35847492..f6bb3c12e 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "fu-device-private.h" @@ -912,13 +911,11 @@ static gchar * fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GError **error) { g_autofree gchar *filename = NULL; - g_autoptr(SoupURI) uri = NULL; /* a local file */ - uri = soup_uri_new (perhapsfn); if (g_file_test (perhapsfn, G_FILE_TEST_EXISTS)) return g_strdup (perhapsfn); - if (uri == NULL) + if (!fu_util_is_url (perhapsfn)) return g_strdup (perhapsfn); /* download the firmware to a cachedir */ @@ -1079,7 +1076,6 @@ fu_util_install_release (FuUtilPrivate *priv, FwupdRelease *rel, GError **error) const gchar *remote_id; const gchar *uri_tmp; g_auto(GStrv) argv = NULL; - g_autoptr(SoupURI) uri = NULL; uri_tmp = fwupd_release_get_uri (rel); if (uri_tmp == NULL) { @@ -1107,8 +1103,8 @@ fu_util_install_release (FuUtilPrivate *priv, FwupdRelease *rel, GError **error) argv = g_new0 (gchar *, 2); /* local remotes may have the firmware already */ - uri = soup_uri_new (uri_tmp); - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && uri == NULL) { + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && + !fu_util_is_url (uri_tmp)) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); argv[0] = g_build_filename (path, uri_tmp, NULL); diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 39b0338ad..d4b430101 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "fu-common.h" #include "fu-device-private.h" @@ -2007,3 +2008,12 @@ fu_util_show_unsupported_warn (void) g_printerr ("%s %s\n", fmt, _("This package has not been validated, it may not work properly.")); #endif } + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) + +gboolean +fu_util_is_url (const gchar *perhaps_url) +{ + g_autoptr(CURLU) h = curl_url (); + return curl_url_set (h, CURLUPART_URL, perhaps_url, 0) == CURLUE_OK; +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index 287178c59..bc3a3b516 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -8,7 +8,6 @@ #include #include -#include /* this is only valid for tools */ #define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) @@ -119,3 +118,4 @@ gboolean fu_util_switch_branch_warning (FwupdDevice *dev, gboolean assume_yes, GError **error); void fu_util_show_unsupported_warn (void); +gboolean fu_util_is_url (const gchar *perhaps_url); diff --git a/src/fu-util.c b/src/fu-util.c index 7c12440a8..82e676a5d 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -584,13 +584,11 @@ fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GErro { g_autofree gchar *filename = NULL; g_autoptr(GBytes) blob = NULL; - g_autoptr(SoupURI) uri = NULL; /* a local file */ if (g_file_test (perhapsfn, G_FILE_TEST_EXISTS)) return g_strdup (perhapsfn); - uri = soup_uri_new (perhapsfn); - if (uri == NULL) + if (!fu_util_is_url (perhapsfn)) return g_strdup (perhapsfn); /* download the firmware to a cachedir */ diff --git a/src/meson.build b/src/meson.build index a8aca163a..68f787bf9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,11 +34,11 @@ fwupdmgr = executable( fwupdplugin_incdir, ], dependencies : [ + libcurl, libxmlb, giounix, gudev, gusb, - soup, sqlite, libarchive, libjsonglib, @@ -67,11 +67,11 @@ fwupdagent = executable( fwupdplugin_incdir, ], dependencies : [ + libcurl, libxmlb, giounix, gudev, gusb, - soup, libjsonglib, ], link_with : [ @@ -102,9 +102,9 @@ fwupdoffline = executable( giounix, gudev, gusb, + libcurl, libjsonglib, libxmlb, - soup, sqlite, ], link_with : [ @@ -153,6 +153,7 @@ fwupdtool = executable( fwupdplugin_incdir, ], dependencies : [ + libcurl, libjcat, libxmlb, libgcab, @@ -160,7 +161,6 @@ fwupdtool = executable( gmodule, gudev, gusb, - soup, sqlite, valgrind, libarchive, @@ -263,7 +263,6 @@ executable( gmodule, gudev, gusb, - soup, sqlite, valgrind, libarchive, @@ -323,7 +322,6 @@ if get_option('tests') gmodule, gudev, gusb, - soup, sqlite, valgrind, libarchive,