Switch from libsoup to libcurl

The former drags on glib-networking and then gsettings-desktop-schemas, which
add over 5Mb to the minimal IoT and CoreOS composes. Everything already uses
libcurl (even NetworkManager!) and so this is an easy way to reduce image size.
This commit is contained in:
Richard Hughes 2020-11-13 13:25:22 +00:00
parent a6e6085365
commit 3a73c342ba
18 changed files with 338 additions and 386 deletions

View File

@ -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:

View File

@ -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}

View File

@ -817,20 +817,20 @@
<package variant="x86_64" />
</distro>
</dependency>
<dependency type="build" id="libsoup2.4-dev">
<dependency type="build" id="libcurl4-gnutls-dev">
<distro id="arch">
<package>libsoup</package>
<package>curl</package>
</distro>
<distro id="centos">
<package>libsoup-devel</package>
<package>libcurl-devel</package>
</distro>
<distro id="fedora">
<package>libsoup-devel</package>
<package>libcurl-devel</package>
</distro>
<distro id="debian">
<control />
<package variant="x86_64" />
<package variant="s390x">libsoup2.4-dev:s390x</package>
<package variant="s390x">libcurl4-gnutls-dev:s390x</package>
<package variant="i386" />
</distro>
<distro id="ubuntu">

View File

@ -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

View File

@ -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"

View File

@ -8,7 +8,7 @@
#include <glib-object.h>
#include <gio/gio.h>
#include <libsoup/soup.h>
#include <curl/curl.h>
#ifdef HAVE_GIO_UNIX
#include <gio/gunixfdlist.h>
#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);
}

View File

@ -6,7 +6,7 @@
#include "config.h"
#include <libsoup/soup.h>
#include <curl/curl.h>
#include <jcat.h>
#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);
}
/**

View File

@ -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,

View File

@ -143,7 +143,6 @@ fwupdplugin_pkgg.generate(
'json-glib-1.0',
'libarchive',
'libgcab-1.0',
'libsoup-2.4',
'xmlb',
'jcat',
],

View File

@ -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

View File

@ -7,7 +7,7 @@
#include "config.h"
#include <json-glib/json-glib.h>
#include <libsoup/soup.h>
#include <curl/curl.h>
#include <string.h>
#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 *

View File

@ -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 : [

View File

@ -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

View File

@ -18,7 +18,6 @@
#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
#include <libsoup/soup.h>
#include <jcat.h>
#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);

View File

@ -13,6 +13,7 @@
#include <gusb.h>
#include <xmlb.h>
#include <fwupd.h>
#include <curl/curl.h>
#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;
}

View File

@ -8,7 +8,6 @@
#include <glib.h>
#include <fwupd.h>
#include <libsoup/soup.h>
/* 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);

View File

@ -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 */

View File

@ -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,