mirror of
https://github.com/flatpak/flatpak.git
synced 2026-05-14 03:24:50 -04:00
utils-http: Drop libsoup2 support in favor of libcurl
A few years ago there was a very painful attempt at porting from libsoup2 to libsoup3. Flatpak libsoup3 support never landed and it seems like a large amount of distros have switched over to libcurl instead. This commit removes libsoup2 support completely instead of growing libsoup3 support. Closes #5915 Closes #4582
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
"image": "mcr.microsoft.com/devcontainers/base:jammy",
|
||||
"features": {
|
||||
"ghcr.io/rocker-org/devcontainer-features/apt-packages:1": {
|
||||
"packages": "policykit-1,libappstream-dev,bison,meson,attr,autopoint,bubblewrap,debhelper,desktop-file-utils,dh-autoreconf,dh-exec,dh-strip-nondeterminism,docbook,docbook-to-man,docbook-xml,docbook-xsl,dwz,fuse,gir1.2-appstreamglib-1.0,gir1.2-freedesktop,gir1.2-gcab-1.0,gir1.2-gdkpixbuf-2.0,gir1.2-json-1.0,gir1.2-ostree-1.0,gir1.2-polkit-1.0,gir1.2-soup-2.4,gobject-introspection,gtk-doc-tools,intltool-debian,libappstream-glib-dev,libappstream-glib8,libarchive-dev,libarchive-zip-perl,libassuan-dev,libattr1-dev,libavahi-glib1,libbrotli-dev,libcap-dev,libdconf-dev,libdebhelper-perl,libdw-dev,libelf-dev,libfile-stripnondeterminism-perl,libfuse-dev,libfuse2,libgcab-1.0-0,libgcab-dev,libgdk-pixbuf2.0-bin,libgdk-pixbuf2.0-dev,libgirepository1.0-dev,libglib2.0-doc,libgpgme-dev,libgpgme11,libjson-glib-dev,libosp5,libostree-1-1,libostree-dev,libostree-doc,libpolkit-agent-1-dev,libpolkit-gobject-1-dev,libpsl-dev,libseccomp-dev,libsoup2.4-dev,libsub-override-perl,libsystemd-dev,libxml2-utils,opensp,ostree,po-debconf,python3-lxml,python3-mako,python3-markdown,python3-markupsafe,python3-packaging,python3-pyparsing,sgml-base,sgml-data,socat,xdg-dbus-proxy,xml-core,xmlto,xsltproc"
|
||||
"packages": "policykit-1,libappstream-dev,bison,meson,attr,autopoint,bubblewrap,debhelper,desktop-file-utils,dh-autoreconf,dh-exec,dh-strip-nondeterminism,docbook,docbook-to-man,docbook-xml,docbook-xsl,dwz,fuse,gir1.2-appstreamglib-1.0,gir1.2-freedesktop,gir1.2-gcab-1.0,gir1.2-gdkpixbuf-2.0,gir1.2-json-1.0,gir1.2-ostree-1.0,gir1.2-polkit-1.0,gobject-introspection,gtk-doc-tools,intltool-debian,libappstream-glib-dev,libappstream-glib8,libarchive-dev,libarchive-zip-perl,libassuan-dev,libattr1-dev,libavahi-glib1,libbrotli-dev,libcap-dev,libdconf-dev,libdebhelper-perl,libdw-dev,libelf-dev,libfile-stripnondeterminism-perl,libfuse-dev,libfuse2,libgcab-1.0-0,libgcab-dev,libgdk-pixbuf2.0-bin,libgdk-pixbuf2.0-dev,libgirepository1.0-dev,libglib2.0-doc,libgpgme-dev,libgpgme11,libjson-glib-dev,libosp5,libostree-1-1,libostree-dev,libostree-doc,libpolkit-agent-1-dev,libpolkit-gobject-1-dev,libpsl-dev,libseccomp-dev,libsub-override-perl,libsystemd-dev,libxml2-utils,opensp,ostree,po-debconf,python3-lxml,python3-mako,python3-markdown,python3-markupsafe,python3-packaging,python3-pyparsing,sgml-base,sgml-data,socat,xdg-dbus-proxy,xml-core,xmlto,xsltproc"
|
||||
}
|
||||
},
|
||||
"runArgs": ["--privileged"]
|
||||
|
||||
10
.github/workflows/check.yml
vendored
10
.github/workflows/check.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
sudo apt-get install -y libglib2.0-dev attr gettext bison dbus gtk-doc-tools \
|
||||
libfuse3-dev ostree libostree-dev libarchive-dev libzstd-dev libcap-dev libattr1-dev libdw-dev libelf-dev python3-pyparsing \
|
||||
libjson-glib-dev shared-mime-info desktop-file-utils libpolkit-agent-1-dev libpolkit-gobject-1-dev \
|
||||
libseccomp-dev libsoup2.4-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libseccomp-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libgirepository1.0-dev libappstream-dev libdconf-dev clang socat meson libdbus-1-dev e2fslibs-dev bubblewrap xdg-dbus-proxy \
|
||||
meson ninja-build libyaml-dev libstemmer-dev gperf itstool libmalcontent-0-dev libxau-dev libgdk-pixbuf2.0-dev openssl
|
||||
# One of the tests wants this
|
||||
@@ -54,7 +54,6 @@ jobs:
|
||||
-Db_sanitize=address,undefined \
|
||||
-Dgir=disabled \
|
||||
-Dgtkdoc=disabled \
|
||||
-Dhttp_backend=curl \
|
||||
-Dinternal_checks=true \
|
||||
-Dinternal_tests=true \
|
||||
-Dsystem_dbus_proxy=xdg-dbus-proxy \
|
||||
@@ -96,7 +95,7 @@ jobs:
|
||||
sudo apt-get install -y libglib2.0-dev attr gettext bison dbus gtk-doc-tools \
|
||||
libfuse-dev ostree libostree-dev libarchive-dev libzstd-dev libcap-dev libattr1-dev libdw-dev libelf-dev python3-pyparsing \
|
||||
libjson-glib-dev shared-mime-info desktop-file-utils libpolkit-agent-1-dev libpolkit-gobject-1-dev \
|
||||
libseccomp-dev libsoup2.4-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libseccomp-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libgirepository1.0-dev libappstream-dev libdconf-dev clang socat meson libdbus-1-dev e2fslibs-dev
|
||||
# One of the tests wants this
|
||||
sudo mkdir /tmp/flatpak-com.example.App-OwnedByRoot
|
||||
@@ -114,7 +113,6 @@ jobs:
|
||||
meson setup \
|
||||
-Dgir=disabled \
|
||||
-Dgtkdoc=disabled \
|
||||
-Dhttp_backend=soup \
|
||||
-Dinternal_checks=true \
|
||||
-Dinternal_tests=true \
|
||||
_build
|
||||
@@ -169,7 +167,7 @@ jobs:
|
||||
sudo apt-get install -y libglib2.0-dev attr gettext bison dbus gtk-doc-tools \
|
||||
libfuse-dev ostree libostree-dev libarchive-dev libzstd-dev libcap-dev libattr1-dev libdw-dev libelf-dev python3-pyparsing \
|
||||
libjson-glib-dev shared-mime-info desktop-file-utils libpolkit-agent-1-dev libpolkit-gobject-1-dev \
|
||||
libseccomp-dev libsoup2.4-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libseccomp-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libgirepository1.0-dev libappstream-dev libdconf-dev clang e2fslibs-dev meson socat libxau-dev libgdk-pixbuf2.0-dev \
|
||||
xmlto
|
||||
- name: Check out flatpak
|
||||
@@ -212,7 +210,7 @@ jobs:
|
||||
sudo apt-get install -y libglib2.0-dev attr gettext bison dbus gtk-doc-tools \
|
||||
libfuse-dev ostree libostree-dev libarchive-dev libzstd-dev libcap-dev libattr1-dev libdw-dev libelf-dev python3-pyparsing \
|
||||
libjson-glib-dev shared-mime-info desktop-file-utils libpolkit-agent-1-dev libpolkit-gobject-1-dev \
|
||||
libseccomp-dev libsoup2.4-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libseccomp-dev libcurl4-openssl-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \
|
||||
libgirepository1.0-dev libappstream-dev libdconf-dev clang socat meson libdbus-1-dev \
|
||||
valgrind e2fslibs-dev meson libxau-dev libgdk-pixbuf2.0-dev
|
||||
- name: Check out flatpak
|
||||
|
||||
@@ -52,7 +52,7 @@ meson test -C _build test-info@user.wrap test-info@system.wrap
|
||||
|
||||
## More info
|
||||
Dependencies you will need include: meson, bison,
|
||||
gettext, gtk-doc, gobject-introspection, libcap, libarchive, libxml2, libsoup,
|
||||
gettext, gtk-doc, gobject-introspection, libcap, libarchive, libxml2, libcurl,
|
||||
gpgme, polkit, libXau, ostree, json-glib, appstream, libseccomp (or their devel
|
||||
packages).
|
||||
|
||||
|
||||
@@ -956,9 +956,6 @@ main (int argc,
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
/* Avoid weird recursive type initialization deadlocks from libsoup */
|
||||
g_type_ensure (G_TYPE_SOCKET);
|
||||
|
||||
if (argc >= 4 && strcmp (argv[1], "complete") == 0)
|
||||
return complete (argc, argv);
|
||||
|
||||
|
||||
@@ -106,9 +106,6 @@ flatpak_installation_class_init (FlatpakInstallationClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = flatpak_installation_finalize;
|
||||
|
||||
/* Avoid weird recursive type initialization deadlocks from libsoup */
|
||||
g_type_ensure (G_TYPE_SOCKET);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
#if defined(HAVE_CURL)
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
/* These macros came from 7.43.0, but we want to check
|
||||
@@ -47,25 +44,6 @@
|
||||
#define CURL_AT_LEAST_VERSION(x,y,z) (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_SOUP)
|
||||
|
||||
#include <libsoup/soup.h>
|
||||
|
||||
#if !defined(SOUP_AUTOCLEANUPS_H) && !defined(__SOUP_AUTOCLEANUPS_H__)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SoupSession, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SoupMessage, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SoupRequest, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SoupRequestHTTP, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SoupURI, soup_uri_free)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
# error "No HTTP backend enabled"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define FLATPAK_HTTP_TIMEOUT_SECS 60
|
||||
|
||||
/* copied from libostree */
|
||||
@@ -393,8 +371,6 @@ flatpak_certificates_free (FlatpakCertificates *certificates)
|
||||
g_free (certificates);
|
||||
}
|
||||
|
||||
#if defined(HAVE_CURL)
|
||||
|
||||
/************************************************************************
|
||||
* Curl implementation *
|
||||
************************************************************************/
|
||||
@@ -754,503 +730,6 @@ flatpak_download_http_uri_once (FlatpakHttpSession *session,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_CURL */
|
||||
|
||||
#if defined(HAVE_SOUP)
|
||||
|
||||
/************************************************************************
|
||||
* Soup implementation *
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* The implementation of /etc/containers/certs.d for Soup is made tricky
|
||||
* because the CA certificate database in Soup is global to the session,
|
||||
* but we share a single sesssion between different hosts that might
|
||||
* need different custom CA certs based on what's configured in certs.d.
|
||||
*
|
||||
* So what we do is make the FlatpakSoupSession multiplex multiple
|
||||
* SoupSessions, depending on the certificates we use. The most common
|
||||
* case, is of course, a single session with no custom certificates.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *user_agent;
|
||||
GHashTable *soup_sessions;
|
||||
} FlatpakSoupSession;
|
||||
|
||||
static guint
|
||||
certificates_hash(const FlatpakCertificates *certificates)
|
||||
{
|
||||
guint hash = 0;
|
||||
|
||||
if (certificates && certificates->ca_cert_file)
|
||||
hash |= 13 * g_str_hash (certificates->ca_cert_file);
|
||||
if (certificates && certificates->client_cert_file)
|
||||
hash |= 17 * g_str_hash (certificates->client_cert_file);
|
||||
if (certificates && certificates->client_key_file)
|
||||
hash |= 23 * g_str_hash (certificates->client_key_file);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
certificates_equal (const FlatpakCertificates *a,
|
||||
const FlatpakCertificates *b)
|
||||
{
|
||||
if (a && b)
|
||||
{
|
||||
return (g_strcmp0(a->ca_cert_file, b->ca_cert_file) == 0 &&
|
||||
g_strcmp0(a->client_cert_file, b->client_cert_file) == 0 &&
|
||||
g_strcmp0(a->client_key_file, b->client_key_file) == 0);
|
||||
}
|
||||
else
|
||||
return a == b;
|
||||
}
|
||||
|
||||
static void
|
||||
certificates_free (FlatpakCertificates *certificates)
|
||||
{
|
||||
if (certificates)
|
||||
flatpak_certificates_free (certificates);
|
||||
}
|
||||
|
||||
static FlatpakSoupSession *
|
||||
flatpak_create_soup_session (const char *user_agent)
|
||||
{
|
||||
FlatpakSoupSession *session = g_new0 (FlatpakSoupSession, 1);
|
||||
|
||||
session->user_agent = g_strdup (user_agent);
|
||||
session->soup_sessions = g_hash_table_new_full ((GHashFunc)certificates_hash,
|
||||
(GEqualFunc)certificates_equal,
|
||||
(GDestroyNotify)certificates_free,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_soup_transfer_error (SoupMessage *msg, GError **error)
|
||||
{
|
||||
GQuark domain = G_IO_ERROR;
|
||||
int code;
|
||||
|
||||
if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
|
||||
return TRUE;
|
||||
|
||||
switch (msg->status_code)
|
||||
{
|
||||
case SOUP_STATUS_CANCELLED:
|
||||
code = G_IO_ERROR_CANCELLED;
|
||||
break;
|
||||
|
||||
case SOUP_STATUS_CANT_RESOLVE:
|
||||
case SOUP_STATUS_CANT_CONNECT:
|
||||
code = G_IO_ERROR_HOST_NOT_FOUND;
|
||||
break;
|
||||
|
||||
case SOUP_STATUS_IO_ERROR:
|
||||
code = G_IO_ERROR_CONNECTION_CLOSED;
|
||||
break;
|
||||
|
||||
default:
|
||||
code = G_IO_ERROR_FAILED;
|
||||
}
|
||||
|
||||
g_set_error (error, domain, code,
|
||||
"Error connecting to server: %s",
|
||||
soup_status_get_phrase (msg->status_code));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The soup input stream was closed */
|
||||
static void
|
||||
stream_closed (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
LoadUriData *data = user_data;
|
||||
GInputStream *stream = G_INPUT_STREAM (source);
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!g_input_stream_close_finish (stream, res, &error))
|
||||
g_warning ("Error closing http stream: %s", error->message);
|
||||
|
||||
if (data->out_tmpfile)
|
||||
{
|
||||
if (!g_output_stream_close (data->out, data->cancellable, &error))
|
||||
{
|
||||
if (data->error == NULL)
|
||||
g_propagate_error (&data->error, g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
g_clear_pointer (&data->out, g_object_unref);
|
||||
}
|
||||
|
||||
data->done = TRUE;
|
||||
g_main_context_wakeup (data->context);
|
||||
}
|
||||
|
||||
/* Got some data from the soup input stream */
|
||||
static void
|
||||
load_uri_read_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
LoadUriData *data = user_data;
|
||||
GInputStream *stream = G_INPUT_STREAM (source);
|
||||
gssize nread;
|
||||
|
||||
nread = g_input_stream_read_finish (stream, res, &data->error);
|
||||
if (nread == -1 || nread == 0)
|
||||
{
|
||||
if (data->progress)
|
||||
data->progress (data->downloaded_bytes, data->user_data);
|
||||
g_input_stream_close_async (stream,
|
||||
G_PRIORITY_DEFAULT, NULL,
|
||||
stream_closed, data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->out != NULL)
|
||||
{
|
||||
gsize n_written;
|
||||
|
||||
if (!g_output_stream_write_all (data->out, data->buffer, nread, &n_written,
|
||||
NULL, &data->error))
|
||||
{
|
||||
data->downloaded_bytes += n_written;
|
||||
g_input_stream_close_async (stream,
|
||||
G_PRIORITY_DEFAULT, NULL,
|
||||
stream_closed, data);
|
||||
return;
|
||||
}
|
||||
|
||||
data->downloaded_bytes += n_written;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (data->content != NULL);
|
||||
data->downloaded_bytes += nread;
|
||||
g_string_append_len (data->content, data->buffer, nread);
|
||||
}
|
||||
|
||||
if (g_get_monotonic_time () - data->last_progress_time > 1 * G_USEC_PER_SEC)
|
||||
{
|
||||
if (data->progress)
|
||||
data->progress (data->downloaded_bytes, data->user_data);
|
||||
data->last_progress_time = g_get_monotonic_time ();
|
||||
}
|
||||
|
||||
g_input_stream_read_async (stream, data->buffer, sizeof (data->buffer),
|
||||
G_PRIORITY_DEFAULT, data->cancellable,
|
||||
load_uri_read_cb, data);
|
||||
}
|
||||
|
||||
/* The http header part of the request is ready */
|
||||
static void
|
||||
load_uri_callback (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
SoupRequestHTTP *request = SOUP_REQUEST_HTTP (source_object);
|
||||
g_autoptr(GInputStream) in = NULL;
|
||||
LoadUriData *data = user_data;
|
||||
|
||||
in = soup_request_send_finish (SOUP_REQUEST (request), res, &data->error);
|
||||
if (in == NULL)
|
||||
{
|
||||
g_main_context_wakeup (data->context);
|
||||
return;
|
||||
}
|
||||
|
||||
g_autoptr(SoupMessage) msg = soup_request_http_get_message ((SoupRequestHTTP *) request);
|
||||
|
||||
if (!check_soup_transfer_error (msg, &data->error))
|
||||
{
|
||||
g_main_context_wakeup (data->context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We correctly made a connection, although it may be a http failure like 404.
|
||||
The status and headers are valid on return, even of a http failure though. */
|
||||
|
||||
data->status = msg->status_code;
|
||||
data->hdr_content_type = g_strdup (soup_message_headers_get_content_type (msg->response_headers, NULL));
|
||||
data->hdr_www_authenticate = g_strdup (soup_message_headers_get_one (msg->response_headers, "WWW-Authenticate"));
|
||||
data->hdr_etag = g_strdup (soup_message_headers_get_one (msg->response_headers, "ETag"));
|
||||
data->hdr_last_modified = g_strdup (soup_message_headers_get_one (msg->response_headers, "Last-Modified"));
|
||||
data->hdr_cache_control = g_strdup (soup_message_headers_get_list (msg->response_headers, "Cache-Control"));
|
||||
data->hdr_expires = g_strdup (soup_message_headers_get_list (msg->response_headers, "Expires"));
|
||||
|
||||
if ((data->flags & FLATPAK_HTTP_FLAGS_NOCHECK_STATUS) == 0 &&
|
||||
!check_http_status (data->status, &data->error))
|
||||
{
|
||||
g_main_context_wakeup (data->context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All is good, write the body to the destination */
|
||||
|
||||
if (data->out_tmpfile)
|
||||
{
|
||||
g_autoptr(GOutputStream) out = NULL;
|
||||
|
||||
if (!glnx_open_tmpfile_linkable_at (data->out_tmpfile_parent_dfd, ".",
|
||||
O_WRONLY, data->out_tmpfile,
|
||||
&data->error))
|
||||
{
|
||||
g_main_context_wakeup (data->context);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (data->out == NULL);
|
||||
|
||||
out = g_unix_output_stream_new (data->out_tmpfile->fd, FALSE);
|
||||
if (data->store_compressed &&
|
||||
g_strcmp0 (soup_message_headers_get_one (msg->response_headers, "Content-Encoding"), "gzip") != 0)
|
||||
{
|
||||
g_autoptr(GZlibCompressor) compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1);
|
||||
data->out = g_converter_output_stream_new (out, G_CONVERTER (compressor));
|
||||
}
|
||||
else
|
||||
{
|
||||
data->out = g_steal_pointer (&out);
|
||||
}
|
||||
}
|
||||
|
||||
g_input_stream_read_async (in, data->buffer, sizeof (data->buffer),
|
||||
G_PRIORITY_DEFAULT, data->cancellable,
|
||||
load_uri_read_cb, data);
|
||||
}
|
||||
|
||||
/* Inline class for providing a pre-configured client certificate; from
|
||||
* libsoup/examples/get.c. By Colin Walters.
|
||||
*/
|
||||
struct _FlatpakTlsInteraction
|
||||
{
|
||||
GTlsInteraction parent_instance;
|
||||
|
||||
GTlsCertificate *cert;
|
||||
};
|
||||
|
||||
struct _FlatpakTlsInteractionClass
|
||||
{
|
||||
GTlsInteractionClass parent_class;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FlatpakTlsInteraction,
|
||||
flatpak_tls_interaction,
|
||||
FLATPAK, TLS_INTERACTION,
|
||||
GTlsInteraction)
|
||||
|
||||
G_DEFINE_TYPE (FlatpakTlsInteraction,
|
||||
flatpak_tls_interaction,
|
||||
G_TYPE_TLS_INTERACTION)
|
||||
|
||||
static GTlsInteractionResult
|
||||
flatpak_tls_interaction_request_certificate (GTlsInteraction *interaction,
|
||||
GTlsConnection *connection,
|
||||
GTlsCertificateRequestFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
FlatpakTlsInteraction *self = FLATPAK_TLS_INTERACTION (interaction);
|
||||
|
||||
g_tls_connection_set_certificate (connection, self->cert);
|
||||
|
||||
return G_TLS_INTERACTION_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
flatpak_tls_interaction_finalize (GObject *object)
|
||||
{
|
||||
FlatpakTlsInteraction *self = FLATPAK_TLS_INTERACTION (object);
|
||||
|
||||
g_clear_object (&self->cert);
|
||||
|
||||
G_OBJECT_CLASS (flatpak_tls_interaction_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
flatpak_tls_interaction_init (FlatpakTlsInteraction *interaction)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
flatpak_tls_interaction_class_init (FlatpakTlsInteractionClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
|
||||
|
||||
object_class->finalize = flatpak_tls_interaction_finalize;
|
||||
|
||||
interaction_class->request_certificate = flatpak_tls_interaction_request_certificate;
|
||||
}
|
||||
|
||||
static FlatpakTlsInteraction *
|
||||
flatpak_tls_interaction_new (GTlsCertificate *cert)
|
||||
{
|
||||
FlatpakTlsInteraction *self = g_object_new (flatpak_tls_interaction_get_type (), NULL);
|
||||
|
||||
self->cert = g_object_ref (cert);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static SoupSession *
|
||||
get_soup_session (FlatpakSoupSession *session, FlatpakCertificates *certificates, GError **error)
|
||||
{
|
||||
SoupSession *soup_session;
|
||||
const char *http_proxy;
|
||||
|
||||
soup_session = g_hash_table_lookup (session->soup_sessions, certificates);
|
||||
if (soup_session)
|
||||
return soup_session;
|
||||
|
||||
soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, session->user_agent,
|
||||
SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
|
||||
SOUP_SESSION_TIMEOUT, FLATPAK_HTTP_TIMEOUT_SECS,
|
||||
SOUP_SESSION_IDLE_TIMEOUT, FLATPAK_HTTP_TIMEOUT_SECS,
|
||||
NULL);
|
||||
if (certificates && certificates->ca_cert_file)
|
||||
g_object_set (soup_session, SOUP_SESSION_SSL_CA_FILE, certificates->ca_cert_file, NULL);
|
||||
else
|
||||
g_object_set (soup_session, SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE, NULL);
|
||||
|
||||
if (certificates && certificates->client_cert_file)
|
||||
{
|
||||
g_autoptr(GTlsCertificate) client_cert = NULL;
|
||||
g_autoptr(GTlsInteraction) interaction = NULL;
|
||||
|
||||
client_cert = g_tls_certificate_new_from_files (certificates->client_cert_file,
|
||||
certificates->client_key_file, error);
|
||||
if (!client_cert)
|
||||
return NULL;
|
||||
|
||||
interaction = G_TLS_INTERACTION (flatpak_tls_interaction_new (client_cert));
|
||||
g_object_set (soup_session, SOUP_SESSION_TLS_INTERACTION, interaction, NULL);
|
||||
}
|
||||
|
||||
http_proxy = g_getenv ("http_proxy");
|
||||
if (http_proxy)
|
||||
{
|
||||
g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy);
|
||||
if (!proxy_uri)
|
||||
g_warning ("Invalid proxy URI '%s'", http_proxy);
|
||||
else
|
||||
g_object_set (soup_session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
|
||||
}
|
||||
|
||||
if (g_getenv ("OSTREE_DEBUG_HTTP"))
|
||||
soup_session_add_feature (soup_session, (SoupSessionFeature *) soup_logger_new (SOUP_LOGGER_LOG_BODY, 500));
|
||||
|
||||
g_hash_table_replace (session->soup_sessions,
|
||||
certificates ? flatpak_certificates_copy (certificates) : NULL,
|
||||
soup_session);
|
||||
|
||||
return soup_session;
|
||||
}
|
||||
|
||||
FlatpakHttpSession *
|
||||
flatpak_create_http_session (const char *user_agent)
|
||||
{
|
||||
return (FlatpakHttpSession *)flatpak_create_soup_session (user_agent);
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_http_session_free (FlatpakHttpSession* http_session)
|
||||
{
|
||||
FlatpakSoupSession *session = (FlatpakSoupSession *)http_session;
|
||||
|
||||
g_hash_table_destroy (session->soup_sessions);
|
||||
g_free (session->user_agent);
|
||||
g_free (session);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
flatpak_download_http_uri_once (FlatpakHttpSession *http_session,
|
||||
LoadUriData *data,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
SoupSession *soup_session;
|
||||
g_autoptr(SoupRequestHTTP) request = NULL;
|
||||
SoupMessage *m;
|
||||
|
||||
g_info ("Loading %s using libsoup", uri);
|
||||
|
||||
soup_session = get_soup_session ((FlatpakSoupSession *)http_session, data->certificates, error);
|
||||
if (!soup_session)
|
||||
return FALSE;
|
||||
|
||||
request = soup_session_request_http (soup_session,
|
||||
(data->flags & FLATPAK_HTTP_FLAGS_HEAD) != 0 ? "HEAD" : "GET",
|
||||
uri, error);
|
||||
if (request == NULL)
|
||||
return FALSE;
|
||||
|
||||
m = soup_request_http_get_message (request);
|
||||
|
||||
if (data->flags & FLATPAK_HTTP_FLAGS_ACCEPT_OCI)
|
||||
soup_message_headers_replace (m->request_headers, "Accept",
|
||||
FLATPAK_OCI_MEDIA_TYPE_IMAGE_MANIFEST ", " FLATPAK_DOCKER_MEDIA_TYPE_IMAGE_MANIFEST2 ", " FLATPAK_OCI_MEDIA_TYPE_IMAGE_INDEX);
|
||||
|
||||
if (data->auth)
|
||||
{
|
||||
g_autofree char *basic_auth = g_strdup_printf ("Basic %s", data->auth);
|
||||
soup_message_headers_replace (m->request_headers, "Authorization", basic_auth);
|
||||
}
|
||||
|
||||
if (data->token)
|
||||
{
|
||||
g_autofree char *bearer_token = g_strdup_printf ("Bearer %s", data->token);
|
||||
soup_message_headers_replace (m->request_headers, "Authorization", bearer_token);
|
||||
}
|
||||
|
||||
if (data->cache_data)
|
||||
{
|
||||
CacheHttpData *cache_data = data->cache_data;
|
||||
|
||||
if (cache_data->etag && cache_data->etag[0])
|
||||
soup_message_headers_replace (m->request_headers, "If-None-Match", cache_data->etag);
|
||||
else if (cache_data->last_modified != 0)
|
||||
{
|
||||
g_autoptr(GDateTime) date = g_date_time_new_from_unix_utc (cache_data->last_modified);
|
||||
g_autofree char *date_str = flatpak_format_http_date (date);
|
||||
soup_message_headers_replace (m->request_headers, "If-Modified-Since", date_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (data->flags & FLATPAK_HTTP_FLAGS_STORE_COMPRESSED)
|
||||
{
|
||||
soup_session_remove_feature_by_type (soup_session, SOUP_TYPE_CONTENT_DECODER);
|
||||
soup_message_headers_replace (m->request_headers, "Accept-Encoding", "gzip");
|
||||
data->store_compressed = TRUE;
|
||||
}
|
||||
else if (!soup_session_has_feature (soup_session, SOUP_TYPE_CONTENT_DECODER))
|
||||
{
|
||||
soup_session_add_feature_by_type (soup_session, SOUP_TYPE_CONTENT_DECODER);
|
||||
data->store_compressed = FALSE;
|
||||
}
|
||||
|
||||
soup_request_send_async (SOUP_REQUEST (request),
|
||||
data->cancellable,
|
||||
load_uri_callback, data);
|
||||
|
||||
while (data->error == NULL && !data->done)
|
||||
g_main_context_iteration (data->context, TRUE);
|
||||
|
||||
if (data->error)
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&data->error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_info ("Received %" G_GUINT64_FORMAT " bytes", data->downloaded_bytes);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SOUP */
|
||||
|
||||
/* Check whether a particular operation should be retried. This is entirely
|
||||
* based on how it failed (if at all) last time, and whether the operation has
|
||||
* some retries left. The retry count is set when the operation is first
|
||||
|
||||
@@ -126,7 +126,6 @@ libflatpak_common_deps = [
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libseccomp_dep,
|
||||
libsoup_dep,
|
||||
libsystemd_dep,
|
||||
libxml_dep,
|
||||
libzstd_dep,
|
||||
|
||||
20
meson.build
20
meson.build
@@ -171,16 +171,7 @@ libarchive_dep = dependency('libarchive', version : '>=2.8.0')
|
||||
glib_dep = dependency('glib-2.0', version : '>=' + required_glib)
|
||||
gio_dep = dependency('gio-2.0', version : '>=' + required_glib)
|
||||
gio_unix_dep = dependency('gio-unix-2.0', version : '>=' + required_glib)
|
||||
|
||||
libcurl_dep = not_found
|
||||
libsoup_dep = not_found
|
||||
|
||||
if get_option('http_backend') == 'soup'
|
||||
libsoup_dep = dependency('libsoup-2.4')
|
||||
else
|
||||
libcurl_dep = dependency('libcurl', version : '>=7.29.0')
|
||||
endif
|
||||
|
||||
libcurl_dep = dependency('libcurl', version : '>=7.29.0')
|
||||
libxml_dep = dependency('libxml-2.0', version : '>=2.4')
|
||||
libzstd_dep = dependency('libzstd', version : '>=0.8.1', required : get_option('libzstd'))
|
||||
dconf_dep = dependency('dconf', version : '>=0.26', required : get_option('dconf'))
|
||||
@@ -388,18 +379,10 @@ if dconf_dep.found()
|
||||
cdata.set('HAVE_DCONF', 1)
|
||||
endif
|
||||
|
||||
if libcurl_dep.found()
|
||||
cdata.set('HAVE_CURL', 1)
|
||||
endif
|
||||
|
||||
if libseccomp_dep.found()
|
||||
cdata.set('ENABLE_SECCOMP', 1)
|
||||
endif
|
||||
|
||||
if libsoup_dep.found()
|
||||
cdata.set('HAVE_SOUP', 1)
|
||||
endif
|
||||
|
||||
if libsystemd_dep.found()
|
||||
cdata.set('HAVE_LIBSYSTEMD', 1)
|
||||
endif
|
||||
@@ -533,7 +516,6 @@ pkgconfig_variables += 'datadir=' + ('${prefix}' / get_option('datadir'))
|
||||
|
||||
pkgconfig_variables += 'datarootdir=' + ('${prefix}' / get_option('datadir'))
|
||||
pkgconfig_variables += 'interfaces_dir=${datadir}/dbus-1/interfaces/'
|
||||
pkgconfig_variables += 'httpbackend=' + get_option('http_backend')
|
||||
|
||||
pkgconfig.generate(
|
||||
libflatpak,
|
||||
|
||||
@@ -55,13 +55,6 @@ option(
|
||||
description : 'build API reference documentation with gtk-doc',
|
||||
value : 'auto',
|
||||
)
|
||||
option(
|
||||
'http_backend',
|
||||
type : 'combo',
|
||||
description : 'library used to implement HTTP',
|
||||
choices : ['curl', 'soup'],
|
||||
value : 'curl',
|
||||
)
|
||||
option(
|
||||
'installed_tests',
|
||||
type : 'boolean',
|
||||
|
||||
@@ -11,7 +11,6 @@ executable(
|
||||
libflatpak_common_dep,
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libsoup_dep,
|
||||
],
|
||||
include_directories : [
|
||||
include_directories('.'),
|
||||
|
||||
@@ -29,7 +29,6 @@ executable(
|
||||
libflatpak_common_dep,
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libsoup_dep,
|
||||
],
|
||||
include_directories : [
|
||||
include_directories('.'),
|
||||
|
||||
@@ -754,7 +754,7 @@ handle_deploy_appstream (FlatpakSystemHelper *object,
|
||||
{
|
||||
g_auto(FlatpakMainContext) context = FLATKPAK_MAIN_CONTEXT_INIT;
|
||||
|
||||
/* This does soup http requests spinning the current mainloop, so we need one
|
||||
/* This does http requests spinning the current mainloop, so we need one
|
||||
for this thread. */
|
||||
flatpak_progress_init_main_context (NULL, &context);
|
||||
/* In the OCI case, we just do the full update, including network i/o, in the
|
||||
|
||||
@@ -10,7 +10,6 @@ executable(
|
||||
libflatpak_common_dep,
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libsoup_dep,
|
||||
polkit_agent_dep,
|
||||
],
|
||||
install : true,
|
||||
|
||||
@@ -128,16 +128,6 @@
|
||||
fun:g_thread_pool_thread_proxy
|
||||
}
|
||||
|
||||
# libsoup thing
|
||||
{
|
||||
ignore_libsoup_file_leak
|
||||
Memcheck:Leak
|
||||
fun:calloc
|
||||
...
|
||||
fun:_g_local_file_new
|
||||
fun:soup_request_file_ensure_file
|
||||
}
|
||||
|
||||
# glibc valgrind fnmatch issue (https://www.mail-archive.com/kde-bugs-dist@kde.org/msg214842.html)
|
||||
{
|
||||
ignore_glibc_fnmatch
|
||||
|
||||
@@ -595,15 +595,6 @@
|
||||
fun:_dl_allocate_tls
|
||||
fun:pthread_create*
|
||||
}
|
||||
{
|
||||
soup_callback_1
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:g_malloc
|
||||
fun:g_source_set_callback
|
||||
fun:soup_add_completion_reffed
|
||||
fun:soup_session_real_kick_queue
|
||||
}
|
||||
{
|
||||
gio_namespace_cache_leak_ns_info
|
||||
Memcheck:Leak
|
||||
|
||||
@@ -10,9 +10,6 @@ main (int argc, char *argv[])
|
||||
const char *url, *dest;
|
||||
int flags = 0;
|
||||
|
||||
/* Avoid weird recursive type initialization deadlocks from libsoup */
|
||||
g_type_ensure (G_TYPE_SOCKET);
|
||||
|
||||
if (argc == 3)
|
||||
{
|
||||
url = argv[1];
|
||||
|
||||
@@ -143,7 +143,6 @@ foreach testcase : c_tests
|
||||
libflatpak_common_base_dep,
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libsoup_dep,
|
||||
libtestlib_dep,
|
||||
] + options.get('extra_dependencies', [])),
|
||||
sources : [name + '.c'] + options.get('extra_sources', []),
|
||||
@@ -208,7 +207,6 @@ executable(
|
||||
libflatpak_common_base_dep,
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libsoup_dep,
|
||||
],
|
||||
include_directories : [common_include_directories],
|
||||
install : get_option('installed_tests'),
|
||||
@@ -228,7 +226,6 @@ executable(
|
||||
libtestlib_dep,
|
||||
libglnx_dep,
|
||||
libostree_dep,
|
||||
libsoup_dep,
|
||||
],
|
||||
install : get_option('installed_tests'),
|
||||
install_dir : installed_testdir,
|
||||
|
||||
Reference in New Issue
Block a user