As osinfo_tree_create_from_location() handles non-local requests, it'd end up relying on GVFS under the hood, which would cause this API to not work when called from an app running as root. In order to avoid this situation, let's rely on libsoup for this cases. It's important to mention that glib minimum version has been bumped to 2.44 as that's the version where g_input_stream_read_all_async() has been introuced. https://gitlab.com/libosinfo/libosinfo/issues/30 Signed-off-by: Fabiano Fidêncio <fidencio@xxxxxxxxxx> --- configure.ac | 4 +- osinfo/libosinfo.syms | 2 + osinfo/osinfo_tree.c | 118 +++++++++++++++++++++++++++++++----------- osinfo/osinfo_tree.h | 14 +++++ 4 files changed, 105 insertions(+), 33 deletions(-) diff --git a/configure.ac b/configure.ac index 02ea1df..0fde62c 100644 --- a/configure.ac +++ b/configure.ac @@ -37,8 +37,8 @@ m4_if(m4_version_compare([2.61a.100], m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) # Keep these two definitions in agreement. -GLIB_MINIMUM_VERSION="2.38" -GLIB_ENCODED_VERSION="GLIB_VERSION_2_38" +GLIB_MINIMUM_VERSION="2.44" +GLIB_ENCODED_VERSION="GLIB_VERSION_2_44" PKG_CHECK_MODULES([LIBXML], [libxml-2.0 >= 2.6.0]) PKG_CHECK_MODULES([LIBXSLT], [libxslt >= 1.0.0]) diff --git a/osinfo/libosinfo.syms b/osinfo/libosinfo.syms index 016d167..6d81e48 100644 --- a/osinfo/libosinfo.syms +++ b/osinfo/libosinfo.syms @@ -595,6 +595,8 @@ LIBOSINFO_1.6.0 { osinfo_media_is_bootable; osinfo_os_get_kernel_url_argument; + + osinfo_tree_error_get_type; } LIBOSINFO_1.5.0; /* Symbols in next release... diff --git a/osinfo/osinfo_tree.c b/osinfo/osinfo_tree.c index 227f2c9..8e98f6c 100644 --- a/osinfo/osinfo_tree.c +++ b/osinfo/osinfo_tree.c @@ -26,14 +26,19 @@ #include <config.h> #include <osinfo/osinfo.h> +#include "osinfo_util_private.h" #include <gio/gio.h> #include <stdlib.h> #include <string.h> #include <glib/gi18n-lib.h> +#include <libsoup/soup.h> typedef struct _CreateFromLocationAsyncData CreateFromLocationAsyncData; struct _CreateFromLocationAsyncData { - GFile *file; + SoupSession *session; + SoupMessage *message; + + gchar *content; gchar *location; gchar *treeinfo; @@ -42,7 +47,8 @@ struct _CreateFromLocationAsyncData { static void create_from_location_async_data_free(CreateFromLocationAsyncData *data) { - g_object_unref(data->file); + g_object_unref(data->session); + g_object_unref(data->message); g_object_unref(data->res); g_slice_free(CreateFromLocationAsyncData, data); @@ -476,7 +482,7 @@ static void on_tree_create_from_location_ready(GObject *source_object, * @error: The location where to store any error, or %NULL * * Creates a new #OsinfoTree for installation tree at @location. The @location - * could be any URI that GIO can handle or a local path. + * could be a http:// or a https:// URI. * * NOTE: Currently this only works for trees with a .treeinfo file * @@ -653,24 +659,57 @@ static void osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData *data, const gchar *treeinfo); +static void on_content_read(GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CreateFromLocationAsyncData *data; + gsize length = 0; + GError *error = NULL; + OsinfoTree *ret; + + data = (CreateFromLocationAsyncData *)user_data; + + if (!g_input_stream_read_all_finish(G_INPUT_STREAM(source), + res, + &length, + &error)) { + g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo content: ")); + g_task_return_error(data->res, error); + create_from_location_async_data_free(data); + } + + if (!(ret = load_keyinfo(data->location, + data->content, + length, + &error))) { + g_prefix_error(&error, _("Failed to process keyinfo file: ")); + g_task_return_error(data->res, error); + goto cleanup; + } + + g_task_return_pointer(data->res, ret, g_object_unref); + + cleanup: + create_from_location_async_data_free(data); +} + static void on_location_read(GObject *source, GAsyncResult *res, gpointer user_data) { CreateFromLocationAsyncData *data; GError *error = NULL; - gchar *content = NULL; - gsize length = 0; - OsinfoTree *ret = NULL; + GInputStream *stream; + goffset content_size; data = (CreateFromLocationAsyncData *)user_data; - if (!g_file_load_contents_finish(G_FILE(source), - res, - &content, - &length, - NULL, - &error)) { + stream = soup_session_send_finish(SOUP_SESSION(source), + res, + &error); + if (stream == NULL || + !SOUP_STATUS_IS_SUCCESSFUL(data->message->status_code)) { /* It means no ".treeinfo" file has been found. Try again, this time * looking for a "treeinfo" file. */ if (g_str_equal(data->treeinfo, ".treeinfo")) { @@ -678,26 +717,28 @@ static void on_location_read(GObject *source, return; } + if (error == NULL) { + g_set_error_literal(&error, + OSINFO_TREE_ERROR, + OSINFO_TREE_ERROR_NO_TREEINFO, + soup_status_get_phrase(data->message->status_code)); + } g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo file: ")); g_task_return_error(data->res, error); create_from_location_async_data_free(data); return; } - if (!(ret = load_keyinfo(data->location, - content, - length, - &error))) { - g_prefix_error(&error, _("Failed to process keyinfo file: ")); - g_task_return_error(data->res, error); - goto cleanup; - } - - g_task_return_pointer(data->res, ret, g_object_unref); + content_size = soup_message_headers_get_content_length(data->message->response_headers); + data->content = g_malloc0(content_size); - cleanup: - create_from_location_async_data_free(data); - g_free(content); + g_input_stream_read_all_async(stream, + data->content, + content_size, + g_task_get_priority(data->res), + g_task_get_cancellable(data->res), + on_content_read, + data); } static void @@ -708,18 +749,33 @@ osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData *data, g_return_if_fail(treeinfo != NULL); + if (!osinfo_util_requires_soup(data->location)) { + GError *error = NULL; + + g_set_error_literal(&error, + OSINFO_TREE_ERROR, + OSINFO_TREE_ERROR_NOT_SUPPORTED_PROTOCOL, + _("URL protocol is not supported")); + + g_task_return_error(data->res, error); + } + location = g_strdup_printf("%s/%s", data->location, treeinfo); - g_clear_object(&data->file); - data->file = g_file_new_for_uri(location); + if (data->session == NULL) + data->session = soup_session_new(); + + g_clear_object(&data->message); + data->message = soup_message_new("GET", location); g_free(data->treeinfo); data->treeinfo = g_strdup(treeinfo); - g_file_load_contents_async(data->file, - g_task_get_cancellable(data->res), - on_location_read, - data); + soup_session_send_async(data->session, + data->message, + g_task_get_cancellable(data->res), + on_location_read, + data); g_free(location); } diff --git a/osinfo/osinfo_tree.h b/osinfo/osinfo_tree.h index 661d06b..c13159b 100644 --- a/osinfo/osinfo_tree.h +++ b/osinfo/osinfo_tree.h @@ -35,6 +35,20 @@ osinfo_tree_error_quark (void) G_GNUC_CONST; #define OSINFO_TREE_ERROR (osinfo_tree_error_quark ()) +/** + * OsinfoTreeError: + * Since: 1.6.0 + * @OSINFO_TREE_ERROR_NO_TREEINFO: No treeinfo found; + * @OSINFO_TREE_ERROR_NOT_SUPPORTED_PROTOCOL: The URL protocol is not supported. + * + * #GError codes used for errors in the #OSINFO_TREE_ERROR domain, during + * reading the treeinfo from a URI. + */ +typedef enum { + OSINFO_TREE_ERROR_NO_TREEINFO, + OSINFO_TREE_ERROR_NOT_SUPPORTED_PROTOCOL +} OsinfoTreeError; + /* * Type macros. -- 2.21.0 _______________________________________________ Libosinfo mailing list Libosinfo@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libosinfo