[Libosinfo] [osinfo-db-tools PATCH v2 1/9] import: Use libsoup for http:// & https:// requests

Fabiano Fidêncio fidencio at redhat.com
Wed Jul 3 10:14:02 UTC 2019


As osinfo-db-import handles non-local requests, it'd end up relying on
GVFS under the hood, which would cause the app to not work when running
as root.

In order to avoid this situation, let's rely on libsoup for this case.

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() has been
introduced.

https://gitlab.com/libosinfo/libosinfo/issues/30

Signed-off-by: Fabiano Fidêncio <fidencio at redhat.com>
---
 configure.ac             |   5 +-
 osinfo-db-tools.spec.in  |   1 +
 tools/Makefile.am        |   2 +
 tools/osinfo-db-import.c | 137 ++++++++++++++++++++++++++++++---------
 4 files changed, 113 insertions(+), 32 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4df1139..d019941 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,13 +63,14 @@ 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.36"
-GLIB_ENCODED_VERSION="GLIB_VERSION_2_36"
+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])
 PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.0.0])
 PKG_CHECK_MODULES([JSON_GLIB], [json-glib-1.0])
+PKG_CHECK_MODULES([LIBSOUP], [libsoup-2.4])
 
 PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $GLIB_MINIMUM_VERSION gobject-2.0 gio-2.0])
 GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=$GLIB_ENCODED_VERSION"
diff --git a/osinfo-db-tools.spec.in b/osinfo-db-tools.spec.in
index 459dde9..8a82c56 100644
--- a/osinfo-db-tools.spec.in
+++ b/osinfo-db-tools.spec.in
@@ -18,6 +18,7 @@ BuildRequires: gettext-devel
 BuildRequires: glib2-devel
 BuildRequires: libxml2-devel >= 2.6.0
 BuildRequires: libxslt-devel >= 1.0.0
+BuildRequires: libsoup-devel
 BuildRequires: libarchive-devel
 BuildRequires: json-glib-devel
 BuildRequires: /usr/bin/pod2man
diff --git a/tools/Makefile.am b/tools/Makefile.am
index e43e85d..f124d4f 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -2,6 +2,7 @@ AM_CFLAGS = $(GOBJECT_CFLAGS) \
 	    $(GIO_CFLAGS)     \
 	    $(GLIB_CFLAGS)    \
 	    $(LIBXML_CFLAGS)  \
+	    $(LIBSOUP_CFLAGS)  \
 	    -DPKGDATADIR="\"$(pkgdatadir)\"" \
 	    -DDATA_DIR="\"$(datadir)\"" \
 	    -DSYSCONFDIR="\"$(sysconfdir)\"" \
@@ -36,6 +37,7 @@ osinfo_db_import_SOURCES = osinfo-db-import.c $(COMMON_SOURCES)
 osinfo_db_import_LDADD = $(GOBJECT_LIBS)	\
 		      $(GIO_LIBS)		\
 		      $(GLIB_LIBS)		\
+		      $(LIBSOUP_LIBS)		\
 		      $(JSON_GLIB_LIBS)	\
 		      $(LIBARCHIVE_LIBS)
 osinfo_db_import_CFLAGS = $(AM_CFLAGS)		\
diff --git a/tools/osinfo-db-import.c b/tools/osinfo-db-import.c
index 675961d..830af3c 100644
--- a/tools/osinfo-db-import.c
+++ b/tools/osinfo-db-import.c
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <archive.h>
 #include <archive_entry.h>
+#include <libsoup/soup.h>
 
 #include "osinfo-db-util.h"
 
@@ -36,6 +37,7 @@
 #define VERSION_FILE "VERSION"
 
 const char *argv0;
+static SoupSession *session = NULL;
 
 static int osinfo_db_import_create_reg(GFile *file,
                                        struct archive *arc,
@@ -139,33 +141,64 @@ static GFile *osinfo_db_import_get_file(GFile *target,
     return g_file_resolve_relative_path(target, tmp);
 }
 
-static int
-osinfo_db_import_download_file(GFile *file,
-                               gchar **source_file)
+static gchar *
+osinfo_db_import_download_file(const gchar *source)
 {
+    GInputStream *stream = NULL;
     GFile *out = NULL;
     GError *err = NULL;
+    SoupMessage *message = NULL;
     gchar *filename = NULL;
-    GFileCopyFlags flags = G_FILE_COPY_OVERWRITE | G_FILE_COPY_BACKUP;
+    gchar *source_file = NULL;
+    gchar *content = NULL;
+    goffset content_size = 0;
+    GFileCreateFlags flags = G_FILE_CREATE_REPLACE_DESTINATION;
     int ret = -1;
 
-    filename = g_file_get_basename(file);
+    filename = g_path_get_basename(source);
     if (filename == NULL)
         goto cleanup;
 
-    *source_file = g_build_filename(g_get_user_cache_dir(), filename, NULL);
-    if (*source_file == NULL)
+    source_file = g_build_filename(g_get_user_cache_dir(), filename, NULL);
+    if (source_file == NULL)
         goto cleanup;
 
-    out = g_file_new_for_path(*source_file);
+    out = g_file_new_for_path(source_file);
     if (out == NULL)
         goto cleanup;
 
-    if (!g_file_copy(file, out, flags, NULL, NULL, NULL, &err)) {
-        gchar *path = g_file_get_path(file);
+    if (session == NULL)
+        session = soup_session_new();
+
+    if (session == NULL)
+        goto cleanup;
+
+    message = soup_message_new("GET", source);
+    if (message == NULL)
+        goto cleanup;
+
+    stream = soup_session_send(session, message, NULL, &err);
+    if (stream == NULL ||
+        !SOUP_STATUS_IS_SUCCESSFUL(message->status_code)) {
+        g_printerr("Could not access %s: %s\n",
+                   source,
+                   err != NULL ? err->message :
+                                 soup_status_get_phrase(message->status_code));
+        goto cleanup;
+    }
+
+    content_size = soup_message_headers_get_content_length(message->response_headers);
+    content = g_malloc0(content_size);
+
+    if (!g_input_stream_read_all(stream, content, content_size, NULL, NULL, &err)) {
+        g_printerr("Could not load the content of %s: %s\n",
+                   source, err->message);
+        goto cleanup;
+    }
+
+    if (!g_file_replace_contents(out, content, content_size, NULL, TRUE, flags, NULL, NULL, &err)) {
         g_printerr("Could not download file \"%s\": %s\n",
-                   path, err->message);
-        g_free(path);
+                   source, err->message);
         goto cleanup;
     }
 
@@ -173,14 +206,20 @@ osinfo_db_import_download_file(GFile *file,
 
  cleanup:
     g_free(filename);
+    g_free(content);
+    g_clear_object(&message);
+    g_clear_object(&stream);
     if (out != NULL)
         g_object_unref(out);
     if (err != NULL)
         g_error_free(err);
-    if (ret != 0 && *source_file != NULL)
-        unlink(*source_file);
+    if (ret != 0 && source_file != NULL) {
+        unlink(source_file);
+        g_free(source_file);
+        source_file = NULL;
+    }
 
-    return ret;
+    return source_file;
 }
 
 static gboolean osinfo_db_get_installed_version(GFile *dir,
@@ -214,18 +253,39 @@ static gboolean osinfo_db_get_installed_version(GFile *dir,
 static gboolean osinfo_db_get_latest_info(gchar **version,
                                           gchar **url)
 {
+    SoupMessage *message = NULL;
+    GInputStream *stream = NULL;
     JsonParser *parser = NULL;
     JsonReader *reader = NULL;
-    GFile *uri = NULL;
     GError *err = NULL;
     gchar *content = NULL;
+    goffset content_size = 0;
     gboolean ret = FALSE;
 
-    uri = g_file_new_for_uri(LATEST_URI);
-    if (uri == NULL)
-        return FALSE;
+    if (session == NULL)
+        session = soup_session_new();
 
-    if (!g_file_load_contents(uri, NULL, &content, NULL, NULL, &err)) {
+    if (session == NULL)
+        goto cleanup;
+
+    message = soup_message_new("GET", LATEST_URI);
+    if (message == NULL)
+        goto cleanup;
+
+    stream = soup_session_send(session, message, NULL, &err);
+    if (stream == NULL ||
+        !SOUP_STATUS_IS_SUCCESSFUL(message->status_code)) {
+        g_printerr("Could not access %s: %s\n",
+                   LATEST_URI,
+                   err != NULL ? err->message :
+                                 soup_status_get_phrase(message->status_code));
+        goto cleanup;
+    }
+
+    content_size = soup_message_headers_get_content_length(message->response_headers);
+    content = g_malloc0(content_size);
+
+    if (!g_input_stream_read_all(stream, content, content_size, NULL, NULL, &err)) {
         g_printerr("Could not load the content of %s: %s\n",
                    LATEST_URI, err->message);
         goto cleanup;
@@ -286,7 +346,7 @@ static gboolean osinfo_db_get_latest_info(gchar **version,
     ret = TRUE;
 
  cleanup:
-    g_object_unref(uri);
+    g_clear_object(&message);
     if (parser != NULL)
         g_object_unref(parser);
     if (reader != NULL)
@@ -297,6 +357,19 @@ static gboolean osinfo_db_get_latest_info(gchar **version,
     return ret;
 }
 
+static gboolean requires_soup(const gchar *source)
+{
+    const gchar *prefixes[] = { "http://", "https://", NULL };
+    gsize i;
+
+    for (i = 0; prefixes[i] != NULL; i++) {
+        if (g_str_has_prefix(source, prefixes[i]))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
 static int osinfo_db_import_extract(GFile *target,
                                     const char *source,
                                     gboolean verbose)
@@ -318,21 +391,21 @@ static int osinfo_db_import_extract(GFile *target,
         source = NULL;
 
     if (source != NULL) {
-        file = g_file_new_for_commandline_arg(source);
-        if (file == NULL)
-            goto cleanup;
+        file_is_native = !requires_soup(source);
 
-        file_is_native = g_file_is_native(file);
-        if (!file_is_native) {
-            if (osinfo_db_import_download_file(file, &source_file) < 0)
+        if (file_is_native) {
+            file = g_file_new_for_commandline_arg(source);
+            if (file == NULL)
                 goto cleanup;
-        } else {
+
             source_file = g_file_get_path(file);
+            g_clear_object(&file);
+        } else {
+            source_file = osinfo_db_import_download_file(source);
         }
+
         if (source_file == NULL)
             goto cleanup;
-
-        g_clear_object(&file);
     }
 
     if ((r = archive_read_open_filename(arc, source_file, 10240)) != ARCHIVE_OK) {
@@ -478,6 +551,7 @@ gint main(gint argc, gchar **argv)
     g_free(installed_version);
     g_free(latest_version);
     g_free(latest_url);
+    g_clear_object(&session);
     g_clear_error(&error);
     g_option_context_free(context);
 
@@ -528,6 +602,9 @@ If run by a privileged account (ie root), the B<local> database
 location will be used by default, otherwise the B<user> location
 will be used.
 
+When passing a non local ARCHIVE-FILE, only http:// and https://
+protocols are supported.
+
 With no ARCHIVE-FILE, or when ARCHIVE-FILE is -, read standard
 input.
 
-- 
2.21.0




More information about the Libosinfo mailing list