2e9f11
From 35bb13da8e53b01a62b8fe45831134df95bdaffc Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garcia Campos <cgarcia@igalia.com>
2e9f11
Date: Tue, 23 Mar 2021 15:59:16 +0100
2e9f11
Subject: [PATCH 01/11] Add support for building with libsoup3
2e9f11
2e9f11
Add soup2 build option, enabled by default. When disabled, it builds
2e9f11
against soup3 instead.
2e9f11
---
2e9f11
 meson.build                                   |  6 ++
2e9f11
 meson_options.txt                             |  2 +
2e9f11
 src/libtracker-sparql/remote/meson.build      |  8 ++-
2e9f11
 .../remote/tracker-remote.vala                | 37 +++++++---
2e9f11
 src/libtracker-sparql/tracker-endpoint-http.c | 68 +++++++++++++++++--
2e9f11
 5 files changed, 105 insertions(+), 16 deletions(-)
2e9f11
2e9f11
diff --git a/meson.build b/meson.build
2e9f11
index ce4c62261..12f93d966 100644
2e9f11
--- a/meson.build
2e9f11
+++ b/meson.build
2e9f11
@@ -52,6 +52,12 @@ libxml2 = dependency('libxml-2.0', version: '> 2.6')
2e9f11
 sqlite = dependency('sqlite3', version: '>' + sqlite_required)
2e9f11
 dbus = dependency('dbus-1')
2e9f11
 
2e9f11
+if get_option('soup2')
2e9f11
+  libsoup = dependency('libsoup-2.4', version: '> 2.40', required: true)
2e9f11
+else
2e9f11
+  libsoup = dependency('libsoup-3.0', version: '>= 2.99.2', required: true)
2e9f11
+endif
2e9f11
+
2e9f11
 libmath = cc.find_library('m', required: false)
2e9f11
 
2e9f11
 if get_option('man')
2e9f11
diff --git a/meson_options.txt b/meson_options.txt
2e9f11
index 99c569502..46e9c130f 100644
2e9f11
--- a/meson_options.txt
2e9f11
+++ b/meson_options.txt
2e9f11
@@ -26,3 +26,5 @@ option('test_utils_dir', type: 'string', value: '',
2e9f11
        description: 'Directory to install trackertestutils Python package (or empty to use the default)')
2e9f11
 option('tests_tap_protocol', type: 'boolean', value: false,
2e9f11
        description: 'Whether to enable TAP protocol on tests')
2e9f11
+option('soup2', type: 'boolean', value: true,
2e9f11
+       description: 'Whether to build with libsoup2')
2e9f11
diff --git a/src/libtracker-sparql/remote/meson.build b/src/libtracker-sparql/remote/meson.build
2e9f11
index f4d589d61..916b72a8a 100644
2e9f11
--- a/src/libtracker-sparql/remote/meson.build
2e9f11
+++ b/src/libtracker-sparql/remote/meson.build
2e9f11
@@ -7,13 +7,19 @@ sources = [
2e9f11
     '../../libtracker-common/libtracker-common.vapi'
2e9f11
 ]
2e9f11
 
2e9f11
+if get_option('soup2')
2e9f11
+  vala_defines = ['--define=SOUP2']
2e9f11
+else
2e9f11
+  vala_defines = []
2e9f11
+endif
2e9f11
+
2e9f11
 libtracker_remote = static_library('tracker-remote', sources,
2e9f11
     dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep],
2e9f11
     c_args: tracker_c_args + [
2e9f11
         '-include', 'config.h',
2e9f11
         '-include', 'libtracker-sparql/tracker-private.h',
2e9f11
     ],
2e9f11
-    vala_args: [
2e9f11
+    vala_args: vala_defines + [
2e9f11
         '--debug',
2e9f11
         '--pkg', 'posix',
2e9f11
         # FIXME: Meson has code to add --target-glib automatically, but it
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vala b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
index 206c237fc..50dc612f3 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
@@ -39,7 +39,11 @@ public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
 	private Soup.Message create_request (string sparql) {
2e9f11
 		var uri = _base_uri + "?query=" + sparql;
2e9f11
 		var message = new Soup.Message ("GET", uri);
2e9f11
+#if SOUP2
2e9f11
 		var headers = message.request_headers;
2e9f11
+#else
2e9f11
+                var headers = message.get_request_headers();
2e9f11
+#endif
2e9f11
 
2e9f11
 		headers.append ("User-Agent", USER_AGENT);
2e9f11
 		headers.append ("Accept", JSON_TYPE);
2e9f11
@@ -48,15 +52,20 @@ public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
 		return message;
2e9f11
 	}
2e9f11
 
2e9f11
-	private Sparql.Cursor create_cursor (Soup.Message message) throws GLib.Error, Sparql.Error {
2e9f11
-		string document = (string) message.response_body.flatten ().data;
2e9f11
+	private Sparql.Cursor create_cursor (Soup.Message message, string document) throws GLib.Error, Sparql.Error {
2e9f11
+#if SOUP2
2e9f11
+                var status_code = message.status_code;
2e9f11
+                var headers = message.response_headers;
2e9f11
+#else
2e9f11
+                var status_code = message.get_status();
2e9f11
+                var headers = message.get_response_headers();
2e9f11
+#endif
2e9f11
 
2e9f11
-		if (message.status_code != Soup.Status.OK) {
2e9f11
+		if (status_code != Soup.Status.OK) {
2e9f11
 			throw new Sparql.Error.UNSUPPORTED ("Unhandled status code %u, document is: %s",
2e9f11
-			                                    message.status_code, document);
2e9f11
+			                                    status_code, document);
2e9f11
 		}
2e9f11
 
2e9f11
-		var headers = message.response_headers;
2e9f11
 		var content_type = headers.get_content_type (null);
2e9f11
 		long length = document.length;
2e9f11
 
2e9f11
@@ -72,20 +81,32 @@ public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
 	public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError {
2e9f11
 		var message = create_request (sparql);
2e9f11
 
2e9f11
+#if SOUP2
2e9f11
 		_session.send_message (message);
2e9f11
+#else
2e9f11
+                var body = _session.send_and_read (message);
2e9f11
+#endif
2e9f11
 
2e9f11
 		if (cancellable != null && cancellable.is_cancelled ())
2e9f11
 			throw new IOError.CANCELLED ("Operation was cancelled");
2e9f11
 
2e9f11
-		return create_cursor (message);
2e9f11
+#if SOUP2
2e9f11
+                return create_cursor (message, (string) message.response_body.flatten ().data);
2e9f11
+#else
2e9f11
+                return create_cursor (message, (string) body.get_data());
2e9f11
+#endif
2e9f11
 	}
2e9f11
 
2e9f11
 	public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError {
2e9f11
 		var message = create_request (sparql);
2e9f11
 
2e9f11
+#if SOUP2
2e9f11
 		yield _session.send_async (message, cancellable);
2e9f11
-
2e9f11
-		return create_cursor (message);
2e9f11
+                return create_cursor (message, (string) message.response_body.flatten ().data);
2e9f11
+#else
2e9f11
+                var body = yield _session.send_and_read_async (message, GLib.Priority.DEFAULT, cancellable);
2e9f11
+                return create_cursor (message, (string) body.get_data());
2e9f11
+#endif
2e9f11
 	}
2e9f11
 
2e9f11
 	public override void close () {
2e9f11
diff --git a/src/libtracker-sparql/tracker-endpoint-http.c b/src/libtracker-sparql/tracker-endpoint-http.c
2e9f11
index de231ca59..5aa82b03d 100644
2e9f11
--- a/src/libtracker-sparql/tracker-endpoint-http.c
2e9f11
+++ b/src/libtracker-sparql/tracker-endpoint-http.c
2e9f11
@@ -41,7 +41,11 @@ struct _TrackerEndpointHttp {
2e9f11
 
2e9f11
 typedef struct {
2e9f11
 	TrackerEndpoint *endpoint;
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        SoupServerMessage *message;
2e9f11
+#else
2e9f11
 	SoupMessage *message;
2e9f11
+#endif
2e9f11
 	GInputStream *istream;
2e9f11
 	GTask *task;
2e9f11
 	TrackerSerializerFormat format;
2e9f11
@@ -90,9 +94,11 @@ handle_request_in_thread (GTask        *task,
2e9f11
 	GError *error = NULL;
2e9f11
 	gssize count;
2e9f11
 
2e9f11
-	g_object_get (request->message,
2e9f11
-	              "response-body", &message_body,
2e9f11
-	              NULL);
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        message_body = soup_server_message_get_response_body (request->message);
2e9f11
+#else
2e9f11
+        message_body = request->message->response_body;
2e9f11
+#endif
2e9f11
 
2e9f11
 	while (!finished) {
2e9f11
 		count = g_input_stream_read (request->istream,
2e9f11
@@ -127,12 +133,22 @@ request_finished_cb (GObject      *object,
2e9f11
 	endpoint_http = TRACKER_ENDPOINT_HTTP (request->endpoint);
2e9f11
 
2e9f11
 	if (!g_task_propagate_boolean (G_TASK (result), &error)) {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (request->message, 500,
2e9f11
+                                                error ? error->message :
2e9f11
+                                                "No error message");
2e9f11
+#else
2e9f11
 		soup_message_set_status_full (request->message, 500,
2e9f11
 		                              error ? error->message :
2e9f11
 		                              "No error message");
2e9f11
+#endif
2e9f11
 		g_clear_error (&error);
2e9f11
 	} else {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (request->message, 200, NULL);
2e9f11
+#else
2e9f11
 		soup_message_set_status (request->message, 200);
2e9f11
+#endif
2e9f11
 	}
2e9f11
 
2e9f11
 	soup_server_unpause_message (endpoint_http->server, request->message);
2e9f11
@@ -153,7 +169,11 @@ query_async_cb (GObject      *object,
2e9f11
 	cursor = tracker_sparql_connection_query_finish (TRACKER_SPARQL_CONNECTION (object),
2e9f11
 	                                                 result, &error);
2e9f11
 	if (error) {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (request->message, 500, error->message);
2e9f11
+#else
2e9f11
 		soup_message_set_status_full (request->message, 500, error->message);
2e9f11
+#endif
2e9f11
 		soup_server_unpause_message (endpoint_http->server, request->message);
2e9f11
 		request_free (request);
2e9f11
 		return;
2e9f11
@@ -167,16 +187,25 @@ query_async_cb (GObject      *object,
2e9f11
 	g_task_run_in_thread (request->task, handle_request_in_thread);
2e9f11
 }
2e9f11
 
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+static gboolean
2e9f11
+pick_format (SoupServerMessage       *message,
2e9f11
+             TrackerSerializerFormat *format)
2e9f11
+#else
2e9f11
 static gboolean
2e9f11
 pick_format (SoupMessage             *message,
2e9f11
              TrackerSerializerFormat *format)
2e9f11
+#endif
2e9f11
 {
2e9f11
 	SoupMessageHeaders *request_headers, *response_headers;
2e9f11
 
2e9f11
-	g_object_get (message,
2e9f11
-	              "request-headers", &request_headers,
2e9f11
-	              "response-headers", &response_headers,
2e9f11
-	              NULL);
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        request_headers = soup_server_message_get_request_headers (message);
2e9f11
+        response_headers = soup_server_message_get_response_headers (message);
2e9f11
+#else
2e9f11
+        request_headers = message->request_headers;
2e9f11
+        response_headers = message->response_headers;
2e9f11
+#endif
2e9f11
 
2e9f11
 	if (soup_message_headers_header_contains (request_headers, "Accept", JSON_TYPE)) {
2e9f11
 		soup_message_headers_set_content_type (response_headers, JSON_TYPE, NULL);
2e9f11
@@ -193,6 +222,14 @@ pick_format (SoupMessage             *message,
2e9f11
 	return FALSE;
2e9f11
 }
2e9f11
 
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+static void
2e9f11
+server_callback (SoupServer        *server,
2e9f11
+	         SoupServerMessage *message,
2e9f11
+                 const char        *path,
2e9f11
+	         GHashTable        *query,
2e9f11
+                 gpointer           user_data)
2e9f11
+#else
2e9f11
 static void
2e9f11
 server_callback (SoupServer        *server,
2e9f11
                  SoupMessage       *message,
2e9f11
@@ -200,6 +237,7 @@ server_callback (SoupServer        *server,
2e9f11
                  GHashTable        *query,
2e9f11
                  SoupClientContext *client,
2e9f11
                  gpointer           user_data)
2e9f11
+#endif
2e9f11
 {
2e9f11
 	TrackerEndpoint *endpoint = user_data;
2e9f11
 	TrackerSparqlConnection *conn;
2e9f11
@@ -209,25 +247,41 @@ server_callback (SoupServer        *server,
2e9f11
 	const gchar *sparql;
2e9f11
 	Request *request;
2e9f11
 
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        remote_address = soup_server_message_get_remote_address (message);
2e9f11
+#else
2e9f11
 	remote_address = soup_client_context_get_remote_address (client);
2e9f11
+#endif
2e9f11
 	if (remote_address) {
2e9f11
 		g_signal_emit (endpoint, signals[BLOCK_REMOTE_ADDRESS], 0,
2e9f11
 		               remote_address, &block);
2e9f11
 	}
2e9f11
 
2e9f11
 	if (block) {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (message, 500, "Remote address disallowed");
2e9f11
+#else
2e9f11
 		soup_message_set_status_full (message, 500, "Remote address disallowed");
2e9f11
+#endif
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
 	sparql = g_hash_table_lookup (query, "query");
2e9f11
 	if (!sparql) {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (message, 500, "No query given");
2e9f11
+#else
2e9f11
 		soup_message_set_status_full (message, 500, "No query given");
2e9f11
+#endif
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
 	if (!pick_format (message, &format)) {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (message, 500, "No recognized accepted formats");
2e9f11
+#else
2e9f11
 		soup_message_set_status_full (message, 500, "No recognized accepted formats");
2e9f11
+#endif
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From da2c34a2d7b7cb717360653c627531d04607a4ee Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Wed, 28 Jul 2021 12:53:47 +0200
2e9f11
Subject: [PATCH 02/11] libtracker-sparql: Allow building against multiple
2e9f11
 versions of libsoup
2e9f11
2e9f11
Tracker is an innocent bystander hindering libsoup3 port, since the
2e9f11
libsoup2/3->tracker->gtk3 dependency chain imposes a libsoup version,
2e9f11
graphical applications using libsoup cannot port at their own pace.
2e9f11
2e9f11
Make our remote code (connection & endpoint) be a private module
2e9f11
that is built against both versions of libsoup (if found), then we
2e9f11
pick one at runtime, with a preference on libsoup3 if libsoup2 .so
2e9f11
file is not seen in the already loaded libraries.
2e9f11
2e9f11
This patch should be reverted ASAP, once we can consider libsoup2
2e9f11
deprecated.
2e9f11
2e9f11
Fixes: https://gitlab.gnome.org/GNOME/tracker/-/issues/320
2e9f11
---
2e9f11
 config.h.meson.in                             |   3 +
2e9f11
 meson.build                                   |  24 +++-
2e9f11
 meson_options.txt                             |   2 -
2e9f11
 src/libtracker-sparql/meson.build             |  60 ++++++++-
2e9f11
 src/libtracker-sparql/remote/meson.build      |  36 ------
2e9f11
 src/libtracker-sparql/tracker-backend.vala    |   5 -
2e9f11
 src/libtracker-sparql/tracker-remote-module.c | 115 ++++++++++++++++++
2e9f11
 7 files changed, 192 insertions(+), 53 deletions(-)
2e9f11
 delete mode 100644 src/libtracker-sparql/remote/meson.build
2e9f11
 create mode 100644 src/libtracker-sparql/tracker-remote-module.c
2e9f11
2e9f11
diff --git a/config.h.meson.in b/config.h.meson.in
2e9f11
index 9d1439e91..4aff15f72 100644
2e9f11
--- a/config.h.meson.in
2e9f11
+++ b/config.h.meson.in
2e9f11
@@ -57,3 +57,6 @@
2e9f11
 
2e9f11
 /* Define to the Tracker minor version */
2e9f11
 #mesondefine TRACKER_MINOR_VERSION
2e9f11
+
2e9f11
+/* Whether RTLD_NOLOAD is defined */
2e9f11
+#mesondefine HAVE_RTLD_NOLOAD
2e9f11
diff --git a/meson.build b/meson.build
2e9f11
index 12f93d966..3b487835b 100644
2e9f11
--- a/meson.build
2e9f11
+++ b/meson.build
2e9f11
@@ -51,14 +51,23 @@ libsoup = dependency('libsoup-2.4', version: '> 2.40', required: true)
2e9f11
 libxml2 = dependency('libxml-2.0', version: '> 2.6')
2e9f11
 sqlite = dependency('sqlite3', version: '>' + sqlite_required)
2e9f11
 dbus = dependency('dbus-1')
2e9f11
+libsoup2 = dependency('libsoup-2.4', version: '> 2.40', required: false)
2e9f11
+libsoup3 = dependency('libsoup-3.0', version: '>= 2.99.2', required: false)
2e9f11
 
2e9f11
-if get_option('soup2')
2e9f11
-  libsoup = dependency('libsoup-2.4', version: '> 2.40', required: true)
2e9f11
-else
2e9f11
-  libsoup = dependency('libsoup-3.0', version: '>= 2.99.2', required: true)
2e9f11
+libmath = cc.find_library('m', required: false)
2e9f11
+libdl = cc.find_library('dl')
2e9f11
+
2e9f11
+soup_backends = ''
2e9f11
+if libsoup2.found()
2e9f11
+  soup_backends = soup_backends + '2.x '
2e9f11
+endif
2e9f11
+if libsoup3.found()
2e9f11
+  soup_backends = soup_backends + '3.x '
2e9f11
 endif
2e9f11
 
2e9f11
-libmath = cc.find_library('m', required: false)
2e9f11
+if not libsoup2.found() and not libsoup3.found()
2e9f11
+  error('At least one of libsoup2 or libsoup3 is required')
2e9f11
+endif
2e9f11
 
2e9f11
 if get_option('man')
2e9f11
   asciidoc = find_program('asciidoc')
2e9f11
@@ -272,6 +281,10 @@ conf.set('TRACKER_MICRO_VERSION', tracker_micro_version)
2e9f11
 conf.set('TRACKER_INTERFACE_AGE', 0)
2e9f11
 conf.set('TRACKER_BINARY_AGE', 100 * tracker_minor_version + tracker_micro_version)
2e9f11
 
2e9f11
+# Check for RTLD_NOLOAD
2e9f11
+have_rtld_noload = cc.has_header_symbol('dlfcn.h', 'RTLD_NOLOAD')
2e9f11
+conf.set('HAVE_RTLD_NOLOAD', have_rtld_noload)
2e9f11
+
2e9f11
 # Config that goes in some other generated files (.desktop, .service, etc)
2e9f11
 conf.set('abs_top_builddir', meson.current_build_dir())
2e9f11
 conf.set('libexecdir', join_paths(get_option('prefix'), get_option('libexecdir')))
2e9f11
@@ -362,6 +375,7 @@ summary = [
2e9f11
   '    Unicode support library:                ' + unicode_library_name,
2e9f11
   '    Use external FTS module:                ' + (not sqlite3_has_builtin_fts5).to_string(),
2e9f11
   '    Build with Stemming support:            ' + have_libstemmer.to_string(),
2e9f11
+  '    Libsoup backends:                       ' + soup_backends,
2e9f11
 ]
2e9f11
 
2e9f11
 if get_option('bash_completion')
2e9f11
diff --git a/meson_options.txt b/meson_options.txt
2e9f11
index 46e9c130f..99c569502 100644
2e9f11
--- a/meson_options.txt
2e9f11
+++ b/meson_options.txt
2e9f11
@@ -26,5 +26,3 @@ option('test_utils_dir', type: 'string', value: '',
2e9f11
        description: 'Directory to install trackertestutils Python package (or empty to use the default)')
2e9f11
 option('tests_tap_protocol', type: 'boolean', value: false,
2e9f11
        description: 'Whether to enable TAP protocol on tests')
2e9f11
-option('soup2', type: 'boolean', value: true,
2e9f11
-       description: 'Whether to build with libsoup2')
2e9f11
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
2e9f11
index 570f4b83b..87b8167cf 100644
2e9f11
--- a/src/libtracker-sparql/meson.build
2e9f11
+++ b/src/libtracker-sparql/meson.build
2e9f11
@@ -20,7 +20,6 @@ libtracker_sparql_c_sources = files(
2e9f11
     'tracker-cursor.c',
2e9f11
     'tracker-endpoint.c',
2e9f11
     'tracker-endpoint-dbus.c',
2e9f11
-    'tracker-endpoint-http.c',
2e9f11
     'tracker-error.c',
2e9f11
     'tracker-namespace-manager.c',
2e9f11
     'tracker-notifier.c',
2e9f11
@@ -54,7 +53,7 @@ libtracker_sparql_c_public_headers = files(
2e9f11
 libtracker_sparql_intermediate = static_library('tracker-sparql-intermediate',
2e9f11
     enum_types,
2e9f11
     libtracker_sparql_c_sources,
2e9f11
-    dependencies: [tracker_common_dep, json_glib, libxml2, libsoup],
2e9f11
+    dependencies: [tracker_common_dep, json_glib, libxml2],
2e9f11
     gnu_symbol_visibility: 'hidden',
2e9f11
 )
2e9f11
 
2e9f11
@@ -63,7 +62,7 @@ sparqlinc = [include_directories('.'), meson.current_build_dir()]
2e9f11
 tracker_sparql_intermediate_dep = declare_dependency(
2e9f11
     link_with: [libtracker_sparql_intermediate],
2e9f11
     include_directories: [srcinc, include_directories('.')],
2e9f11
-    dependencies: [ tracker_sparql_vapi_dep ],
2e9f11
+    dependencies: [ tracker_sparql_vapi_dep, tracker_data_dep ],
2e9f11
     sources: enum_types[1],
2e9f11
 )
2e9f11
 
2e9f11
@@ -88,13 +87,61 @@ install_data(
2e9f11
 
2e9f11
 subdir('bus')
2e9f11
 subdir('direct')
2e9f11
-subdir('remote')
2e9f11
+
2e9f11
+tracker_remote_dependencies = [json_glib, libxml2]
2e9f11
+
2e9f11
+remote_sources = [
2e9f11
+    'tracker-endpoint-http.c',
2e9f11
+    'remote/tracker-json-cursor.vala',
2e9f11
+    'remote/tracker-xml-cursor.vala',
2e9f11
+    'remote/tracker-remote.vala',
2e9f11
+]
2e9f11
+
2e9f11
+if libsoup2.found()
2e9f11
+    libtracker_remote_soup2 = shared_module('tracker-remote-soup2', remote_sources,
2e9f11
+        dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep, libsoup2],
2e9f11
+        c_args: tracker_c_args + [
2e9f11
+            '-include', 'config.h',
2e9f11
+            '-include', 'libtracker-sparql/tracker-private.h',
2e9f11
+        ],
2e9f11
+        vala_args: [
2e9f11
+            '--debug',
2e9f11
+            '--pkg', 'posix',
2e9f11
+            # FIXME: Meson has code to add --target-glib automatically, but it
2e9f11
+            # doesn't seem to work here.
2e9f11
+            '--target-glib', glib_required,
2e9f11
+            '--define=SOUP2',
2e9f11
+        ],
2e9f11
+        install: true,
2e9f11
+        install_dir: tracker_internal_libs_dir,
2e9f11
+    )
2e9f11
+endif
2e9f11
+
2e9f11
+if libsoup3.found()
2e9f11
+    libtracker_remote_soup3 = shared_module('tracker-remote-soup3', remote_sources,
2e9f11
+        dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep, libsoup3],
2e9f11
+        c_args: tracker_c_args + [
2e9f11
+            '-include', 'config.h',
2e9f11
+            '-include', 'libtracker-sparql/tracker-private.h',
2e9f11
+        ],
2e9f11
+        vala_args: [
2e9f11
+            '--debug',
2e9f11
+            '--pkg', 'posix',
2e9f11
+            # FIXME: Meson has code to add --target-glib automatically, but it
2e9f11
+            # doesn't seem to work here.
2e9f11
+            '--target-glib', glib_required,
2e9f11
+        ],
2e9f11
+        install: true,
2e9f11
+        install_dir: tracker_internal_libs_dir,
2e9f11
+    )
2e9f11
+endif
2e9f11
 
2e9f11
 libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
2e9f11
     '../libtracker-common/libtracker-common.vapi',
2e9f11
     '../libtracker-data/libtracker-data.vapi',
2e9f11
     'direct/tracker-direct.vapi',
2e9f11
     'tracker-backend.vala',
2e9f11
+    'tracker-remote-module.c',
2e9f11
     tracker_gresources,
2e9f11
 
2e9f11
     gnu_symbol_visibility: 'hidden',
2e9f11
@@ -107,11 +154,14 @@ libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
2e9f11
 
2e9f11
     c_args: [
2e9f11
 	'-include', 'libtracker-sparql/tracker-private.h',
2e9f11
+        '-DPRIVATE_LIBDIR="@0@"'.format(tracker_internal_libs_dir),
2e9f11
+        '-DBUILD_LIBDIR="@0@"'.format(meson.current_build_dir()),
2e9f11
+        '-DBUILDROOT="@0@"'.format(meson.project_build_root()),
2e9f11
     ],
2e9f11
 
2e9f11
     link_whole: [libtracker_sparql_intermediate],
2e9f11
 
2e9f11
-    dependencies: [tracker_common_dep, tracker_sparql_remote_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, tracker_sparql_vapi_dep],
2e9f11
+    dependencies: [tracker_common_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, tracker_sparql_vapi_dep, gmodule, libdl],
2e9f11
 )
2e9f11
 
2e9f11
 tracker_sparql_dep = declare_dependency(
2e9f11
diff --git a/src/libtracker-sparql/remote/meson.build b/src/libtracker-sparql/remote/meson.build
2e9f11
deleted file mode 100644
2e9f11
index 916b72a8a..000000000
2e9f11
--- a/src/libtracker-sparql/remote/meson.build
2e9f11
+++ /dev/null
2e9f11
@@ -1,36 +0,0 @@
2e9f11
-tracker_remote_dependencies = [json_glib, libsoup, libxml2]
2e9f11
-
2e9f11
-sources = [
2e9f11
-    'tracker-json-cursor.vala',
2e9f11
-    'tracker-xml-cursor.vala',
2e9f11
-    'tracker-remote.vala',
2e9f11
-    '../../libtracker-common/libtracker-common.vapi'
2e9f11
-]
2e9f11
-
2e9f11
-if get_option('soup2')
2e9f11
-  vala_defines = ['--define=SOUP2']
2e9f11
-else
2e9f11
-  vala_defines = []
2e9f11
-endif
2e9f11
-
2e9f11
-libtracker_remote = static_library('tracker-remote', sources,
2e9f11
-    dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep],
2e9f11
-    c_args: tracker_c_args + [
2e9f11
-        '-include', 'config.h',
2e9f11
-        '-include', 'libtracker-sparql/tracker-private.h',
2e9f11
-    ],
2e9f11
-    vala_args: vala_defines + [
2e9f11
-        '--debug',
2e9f11
-        '--pkg', 'posix',
2e9f11
-        # FIXME: Meson has code to add --target-glib automatically, but it
2e9f11
-        # doesn't seem to work here.
2e9f11
-        '--target-glib', glib_required,
2e9f11
-    ],
2e9f11
-    gnu_symbol_visibility: 'hidden',
2e9f11
-)
2e9f11
-
2e9f11
-tracker_sparql_remote_dep = declare_dependency(
2e9f11
-    link_with: libtracker_remote,
2e9f11
-    include_directories: include_directories('.'),
2e9f11
-    dependencies: tracker_remote_dependencies,
2e9f11
-)
2e9f11
diff --git a/src/libtracker-sparql/tracker-backend.vala b/src/libtracker-sparql/tracker-backend.vala
2e9f11
index ae6313118..af1102d5a 100644
2e9f11
--- a/src/libtracker-sparql/tracker-backend.vala
2e9f11
+++ b/src/libtracker-sparql/tracker-backend.vala
2e9f11
@@ -22,11 +22,6 @@
2e9f11
  * effect of printing the 'help' message if TRACKER_DEBUG=help is set.
2e9f11
  */
2e9f11
 
2e9f11
-public static Tracker.Sparql.Connection tracker_sparql_connection_remote_new (string url_base) {
2e9f11
-	Tracker.get_debug_flags ();
2e9f11
-	return new Tracker.Remote.Connection (url_base);
2e9f11
-}
2e9f11
-
2e9f11
 public static Tracker.Sparql.Connection tracker_sparql_connection_bus_new (string service, string? object_path, DBusConnection? conn) throws Tracker.Sparql.Error, IOError, DBusError, GLib.Error {
2e9f11
 	Tracker.get_debug_flags ();
2e9f11
 
2e9f11
diff --git a/src/libtracker-sparql/tracker-remote-module.c b/src/libtracker-sparql/tracker-remote-module.c
2e9f11
new file mode 100644
2e9f11
index 000000000..2ca0fd181
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/tracker-remote-module.c
2e9f11
@@ -0,0 +1,115 @@
2e9f11
+/* Yuck */
2e9f11
+
2e9f11
+#include "config.h"
2e9f11
+
2e9f11
+#include <gio/gio.h>
2e9f11
+#include <tracker-sparql.h>
2e9f11
+#include <dlfcn.h>
2e9f11
+
2e9f11
+#define LIBSOUP_2_SONAME "libsoup-2.4.so.1"
2e9f11
+
2e9f11
+static gboolean initialized = FALSE;
2e9f11
+
2e9f11
+GType (* remote_endpoint_get_type) (void) = NULL;
2e9f11
+
2e9f11
+TrackerEndpoint * (* remote_endpoint_new) (TrackerSparqlConnection  *sparql_connection,
2e9f11
+                                           guint                     port,
2e9f11
+                                           GTlsCertificate          *certificate,
2e9f11
+                                           GCancellable             *cancellable,
2e9f11
+                                           GError                  **error) = NULL;
2e9f11
+TrackerSparqlConnection * (* remote_connection_new) (const gchar *url_base) = NULL;
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_init_remote (void)
2e9f11
+{
2e9f11
+	const char *modules[3] = { 0 };
2e9f11
+	gpointer handle = NULL;
2e9f11
+	gint i = 0;
2e9f11
+
2e9f11
+	if (initialized)
2e9f11
+		return;
2e9f11
+
2e9f11
+	g_assert (g_module_supported ());
2e9f11
+
2e9f11
+#ifdef HAVE_RTLD_NOLOAD
2e9f11
+	if ((handle = dlopen (LIBSOUP_2_SONAME, RTLD_NOW | RTLD_NOLOAD))) {
2e9f11
+		/* Force load of soup2 module */
2e9f11
+		modules[0] = "libtracker-remote-soup2.so";
2e9f11
+	} else
2e9f11
+#endif
2e9f11
+	{
2e9f11
+		modules[0] = "libtracker-remote-soup3.so";
2e9f11
+		modules[1] = "libtracker-remote-soup2.so";
2e9f11
+	}
2e9f11
+
2e9f11
+	g_clear_pointer (&handle, dlclose);
2e9f11
+
2e9f11
+	for (i = 0; modules[i]; i++) {
2e9f11
+		GModule *remote_module;
2e9f11
+		gchar *module_path;
2e9f11
+
2e9f11
+		if (g_strcmp0 (g_get_current_dir (), BUILDROOT) == 0) {
2e9f11
+			/* Detect in-build runtime of this code, this may happen
2e9f11
+			 * building introspection information or running tests.
2e9f11
+			 * We want the in-tree modules to be loaded then.
2e9f11
+			 */
2e9f11
+			module_path = g_strdup_printf (BUILD_LIBDIR "/%s", modules[i]);
2e9f11
+		} else {
2e9f11
+			module_path = g_strdup_printf (PRIVATE_LIBDIR "/%s", modules[i]);
2e9f11
+		}
2e9f11
+
2e9f11
+		remote_module = g_module_open (module_path,
2e9f11
+		                               G_MODULE_BIND_LAZY |
2e9f11
+		                               G_MODULE_BIND_LOCAL);
2e9f11
+		g_free (module_path);
2e9f11
+
2e9f11
+		if (!remote_module)
2e9f11
+			continue;
2e9f11
+
2e9f11
+		if (!g_module_symbol (remote_module, "tracker_endpoint_http_get_type", (gpointer *) &remote_endpoint_get_type) ||
2e9f11
+		    !g_module_symbol (remote_module, "tracker_endpoint_http_new", (gpointer *) &remote_endpoint_new) ||
2e9f11
+		    !g_module_symbol (remote_module, "tracker_remote_connection_new", (gpointer *) &remote_connection_new)) {
2e9f11
+			g_clear_pointer (&remote_module, g_module_close);
2e9f11
+			continue;
2e9f11
+		}
2e9f11
+
2e9f11
+		g_module_make_resident (remote_module);
2e9f11
+		g_module_close (remote_module);
2e9f11
+		initialized = TRUE;
2e9f11
+		return;
2e9f11
+	}
2e9f11
+
2e9f11
+	g_assert_not_reached ();
2e9f11
+}
2e9f11
+
2e9f11
+GType
2e9f11
+tracker_endpoint_http_get_type (void)
2e9f11
+{
2e9f11
+	tracker_init_remote ();
2e9f11
+
2e9f11
+	return remote_endpoint_get_type ();
2e9f11
+}
2e9f11
+
2e9f11
+TrackerEndpointHttp *
2e9f11
+tracker_endpoint_http_new (TrackerSparqlConnection  *sparql_connection,
2e9f11
+                           guint                     port,
2e9f11
+                           GTlsCertificate          *certificate,
2e9f11
+                           GCancellable             *cancellable,
2e9f11
+                           GError                  **error)
2e9f11
+{
2e9f11
+	tracker_init_remote ();
2e9f11
+
2e9f11
+	return (TrackerEndpointHttp *) remote_endpoint_new (sparql_connection,
2e9f11
+	                                                    port,
2e9f11
+	                                                    certificate,
2e9f11
+	                                                    cancellable,
2e9f11
+	                                                    error);
2e9f11
+}
2e9f11
+
2e9f11
+TrackerSparqlConnection *
2e9f11
+tracker_sparql_connection_remote_new (const gchar *url_base)
2e9f11
+{
2e9f11
+	tracker_init_remote ();
2e9f11
+
2e9f11
+	return remote_connection_new (url_base);
2e9f11
+}
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 52324bd629a5446594717a2e782a85913821b447 Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Wed, 10 Nov 2021 23:16:37 +0200
2e9f11
Subject: [PATCH 03/11] libtracker-sparql: Escape query in remote connection
2e9f11
2e9f11
This is embedded in the URI, so should get proper escaping to avoid
2e9f11
misinterpretation with certain characters.
2e9f11
---
2e9f11
 src/libtracker-sparql/remote/tracker-remote.vala | 2 +-
2e9f11
 1 file changed, 1 insertion(+), 1 deletion(-)
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vala b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
index 50dc612f3..252d70a40 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
@@ -37,7 +37,7 @@ public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
 	}
2e9f11
 
2e9f11
 	private Soup.Message create_request (string sparql) {
2e9f11
-		var uri = _base_uri + "?query=" + sparql;
2e9f11
+		var uri = _base_uri + "?query=" + GLib.Uri.escape_string (sparql, null, false);
2e9f11
 		var message = new Soup.Message ("GET", uri);
2e9f11
 #if SOUP2
2e9f11
 		var headers = message.request_headers;
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 68592b8a44305937134d94dfc3dfdf8444485f7b Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Wed, 10 Nov 2021 23:28:11 +0200
2e9f11
Subject: [PATCH 04/11] libtracker-data: Refactor some soup2/3 code handling
2e9f11
2e9f11
Remove the need for one ifdef, and make a consistent handling of empty
2e9f11
responses.
2e9f11
---
2e9f11
 src/libtracker-sparql/remote/tracker-remote.vala | 13 +++++++------
2e9f11
 1 file changed, 7 insertions(+), 6 deletions(-)
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vala b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
index 252d70a40..f29a989ad 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
@@ -83,18 +83,19 @@ public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
 
2e9f11
 #if SOUP2
2e9f11
 		_session.send_message (message);
2e9f11
+		var data = (string) message.response_body.flatten ().data;
2e9f11
 #else
2e9f11
-                var body = _session.send_and_read (message);
2e9f11
+		var body = _session.send_and_read (message);
2e9f11
+		var data = (string) body.get_data();
2e9f11
 #endif
2e9f11
 
2e9f11
+		if (data == null || data == "")
2e9f11
+			throw new Sparql.Error.UNSUPPORTED ("Empty response");
2e9f11
+
2e9f11
 		if (cancellable != null && cancellable.is_cancelled ())
2e9f11
 			throw new IOError.CANCELLED ("Operation was cancelled");
2e9f11
 
2e9f11
-#if SOUP2
2e9f11
-                return create_cursor (message, (string) message.response_body.flatten ().data);
2e9f11
-#else
2e9f11
-                return create_cursor (message, (string) body.get_data());
2e9f11
-#endif
2e9f11
+                return create_cursor (message, (string) data);
2e9f11
 	}
2e9f11
 
2e9f11
 	public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError {
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 6f3b7bc85b715d1071cfb39ff3f10ecc96395ee8 Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Wed, 10 Nov 2021 23:43:50 +0200
2e9f11
Subject: [PATCH 05/11] libtracker-data: Add remote TrackerSparqlStatement
2e9f11
 implementation
2e9f11
2e9f11
Implement this object for remote connections to increase API consistency.
2e9f11
Underneath, our very own SPARQL parser is used to do raw string replacements
2e9f11
on the actual query being sent.
2e9f11
2e9f11
Besides API consistence, this also has the benefit to make ~var bindings
2e9f11
work with other SPARQL endpoints that are not Tracker's.
2e9f11
---
2e9f11
 src/libtracker-sparql/meson.build             |   8 +-
2e9f11
 .../remote/tracker-remote-statement.c         | 401 ++++++++++++++++++
2e9f11
 .../remote/tracker-remote-statement.h         |  32 ++
2e9f11
 .../remote/tracker-remote.vala                |   4 +
2e9f11
 .../remote/tracker-remote.vapi                |   6 +
2e9f11
 5 files changed, 450 insertions(+), 1 deletion(-)
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-remote-statement.c
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-remote-statement.h
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-remote.vapi
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
2e9f11
index 87b8167cf..21b9b5a28 100644
2e9f11
--- a/src/libtracker-sparql/meson.build
2e9f11
+++ b/src/libtracker-sparql/meson.build
2e9f11
@@ -90,8 +90,14 @@ subdir('direct')
2e9f11
 
2e9f11
 tracker_remote_dependencies = [json_glib, libxml2]
2e9f11
 
2e9f11
-remote_sources = [
2e9f11
+libtracker_sparql_remote_c_sources = files (
2e9f11
     'tracker-endpoint-http.c',
2e9f11
+    'remote/tracker-remote-statement.c',
2e9f11
+)
2e9f11
+
2e9f11
+remote_sources = [
2e9f11
+    libtracker_sparql_remote_c_sources,
2e9f11
+    'remote/tracker-remote.vapi',
2e9f11
     'remote/tracker-json-cursor.vala',
2e9f11
     'remote/tracker-xml-cursor.vala',
2e9f11
     'remote/tracker-remote.vala',
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote-statement.c b/src/libtracker-sparql/remote/tracker-remote-statement.c
2e9f11
new file mode 100644
2e9f11
index 000000000..6ca9f5246
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote-statement.c
2e9f11
@@ -0,0 +1,401 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2021, Red Hat Inc.
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#include "config.h"
2e9f11
+
2e9f11
+#include "tracker-remote-statement.h"
2e9f11
+
2e9f11
+#include <libtracker-common/tracker-common.h>
2e9f11
+#include <libtracker-data/tracker-sparql-grammar.h>
2e9f11
+#include <libtracker-data/tracker-sparql-parser.h>
2e9f11
+#include <libtracker-sparql/tracker-private.h>
2e9f11
+
2e9f11
+struct _TrackerRemoteStatement
2e9f11
+{
2e9f11
+	TrackerSparqlStatement parent_instance;
2e9f11
+	TrackerNodeTree *parser_tree;
2e9f11
+	GHashTable *bindings;
2e9f11
+};
2e9f11
+
2e9f11
+G_DEFINE_TYPE (TrackerRemoteStatement,
2e9f11
+               tracker_remote_statement,
2e9f11
+               TRACKER_TYPE_SPARQL_STATEMENT)
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_finalize (GObject *object)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (object);
2e9f11
+
2e9f11
+	if (remote_stmt->parser_tree)
2e9f11
+		tracker_node_tree_free (remote_stmt->parser_tree);
2e9f11
+	g_hash_table_unref (remote_stmt->bindings);
2e9f11
+
2e9f11
+	G_OBJECT_CLASS (tracker_remote_statement_parent_class)->finalize (object);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_bind_int (TrackerSparqlStatement *stmt,
2e9f11
+                                   const gchar            *name,
2e9f11
+                                   gint64                  value)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	GValue *val;
2e9f11
+
2e9f11
+	val = g_new0 (GValue, 1);
2e9f11
+	g_value_init (val, G_TYPE_INT64);
2e9f11
+	g_value_set_int64 (val, value);
2e9f11
+
2e9f11
+	g_hash_table_insert (remote_stmt->bindings,
2e9f11
+	                     g_strdup (name),
2e9f11
+	                     val);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_bind_boolean (TrackerSparqlStatement *stmt,
2e9f11
+                                       const gchar            *name,
2e9f11
+                                       gboolean                value)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	GValue *val;
2e9f11
+
2e9f11
+	val = g_new0 (GValue, 1);
2e9f11
+	g_value_init (val, G_TYPE_BOOLEAN);
2e9f11
+	g_value_set_boolean (val, value);
2e9f11
+
2e9f11
+	g_hash_table_insert (remote_stmt->bindings,
2e9f11
+	                     g_strdup (name),
2e9f11
+	                     val);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_bind_string (TrackerSparqlStatement *stmt,
2e9f11
+                                      const gchar            *name,
2e9f11
+                                      const gchar            *value)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	GValue *val;
2e9f11
+
2e9f11
+	val = g_new0 (GValue, 1);
2e9f11
+	g_value_init (val, G_TYPE_STRING);
2e9f11
+	g_value_set_string (val, value);
2e9f11
+
2e9f11
+	g_hash_table_insert (remote_stmt->bindings,
2e9f11
+	                     g_strdup (name),
2e9f11
+	                     val);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_bind_double (TrackerSparqlStatement *stmt,
2e9f11
+                                      const gchar            *name,
2e9f11
+                                      gdouble                 value)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	GValue *val;
2e9f11
+
2e9f11
+	val = g_new0 (GValue, 1);
2e9f11
+	g_value_init (val, G_TYPE_DOUBLE);
2e9f11
+	g_value_set_double (val, value);
2e9f11
+
2e9f11
+	g_hash_table_insert (remote_stmt->bindings,
2e9f11
+	                     g_strdup (name),
2e9f11
+	                     val);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+append_gvalue (GString *str,
2e9f11
+               const GValue  *value)
2e9f11
+{
2e9f11
+	if (G_VALUE_HOLDS_BOOLEAN (value)) {
2e9f11
+		g_string_append_printf (str, "%s",
2e9f11
+		                        g_value_get_boolean (value) ?
2e9f11
+		                        "true" : "false");
2e9f11
+	} else if (G_VALUE_HOLDS_INT64 (value)) {
2e9f11
+		g_string_append_printf (str, "%" G_GINT64_FORMAT,
2e9f11
+		                        g_value_get_int64 (value));
2e9f11
+	} else if (G_VALUE_HOLDS_DOUBLE (value)) {
2e9f11
+		gchar buf[G_ASCII_DTOSTR_BUF_SIZE + 1];
2e9f11
+
2e9f11
+		g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
2e9f11
+		g_string_append (str, buf);
2e9f11
+	} else if (G_VALUE_TYPE (value) == G_TYPE_DATE_TIME) {
2e9f11
+		GDateTime *datetime;
2e9f11
+		gchar *datetime_str;
2e9f11
+
2e9f11
+		datetime = g_value_get_boxed (value);
2e9f11
+		datetime_str = tracker_date_format_iso8601 (datetime);
2e9f11
+		g_string_append_printf (str, "\"%s\"", datetime_str);
2e9f11
+		g_free (datetime_str);
2e9f11
+	} else if (G_VALUE_HOLDS_STRING (value)) {
2e9f11
+		const gchar *val = g_value_get_string (value);
2e9f11
+		int len = strlen (val);
2e9f11
+		gchar *end;
2e9f11
+		gboolean is_number = FALSE;
2e9f11
+
2e9f11
+		/* Try to detect numbers anyway, since we use to allow
2e9f11
+		 * loose typing in other connection types.
2e9f11
+		 */
2e9f11
+		g_ascii_strtoll (val, &end, 10);
2e9f11
+		is_number = (end == &val[len]);
2e9f11
+
2e9f11
+		if (!is_number) {
2e9f11
+			g_ascii_strtod (val, &end;;
2e9f11
+			is_number = (end == &val[len]);
2e9f11
+		}
2e9f11
+
2e9f11
+		if (is_number)
2e9f11
+			g_string_append (str, val);
2e9f11
+		else
2e9f11
+			g_string_append_printf (str, "\"%s\"", val);
2e9f11
+	}
2e9f11
+}
2e9f11
+
2e9f11
+static gchar *
2e9f11
+apply_bindings (TrackerSparqlStatement  *stmt,
2e9f11
+                GHashTable              *bindings,
2e9f11
+                GError                 **error)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	const gchar *query = tracker_sparql_statement_get_sparql (stmt);
2e9f11
+	GString *str = g_string_new (NULL);
2e9f11
+	TrackerParserNode *node = tracker_node_tree_get_root (remote_stmt->parser_tree);
2e9f11
+
2e9f11
+	for (node = tracker_sparql_parser_tree_find_first (node, TRUE);
2e9f11
+	     node;
2e9f11
+	     node = tracker_sparql_parser_tree_find_next (node, TRUE)) {
2e9f11
+		const TrackerGrammarRule *rule;
2e9f11
+		gssize start, end;
2e9f11
+
2e9f11
+		if (!tracker_parser_node_get_extents (node, &start, &end)) {
2e9f11
+			/* Skip over 0-len nodes */
2e9f11
+			continue;
2e9f11
+		}
2e9f11
+
2e9f11
+		rule = tracker_parser_node_get_rule (node);
2e9f11
+
2e9f11
+		if (tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL,
2e9f11
+		                               TERMINAL_TYPE_PARAMETERIZED_VAR)) {
2e9f11
+			gchar *param_name;
2e9f11
+			const GValue *value;
2e9f11
+
2e9f11
+			param_name = g_strndup (&query[start], end - start);
2e9f11
+			value = g_hash_table_lookup (bindings, &param_name[1]);
2e9f11
+			if (!value) {
2e9f11
+				g_set_error (error,
2e9f11
+				             TRACKER_SPARQL_ERROR,
2e9f11
+				             TRACKER_SPARQL_ERROR_PARSE,
2e9f11
+				             "No binding found for variable %s",
2e9f11
+				             param_name);
2e9f11
+				g_string_free (str, TRUE);
2e9f11
+				g_free (param_name);
2e9f11
+				return NULL;
2e9f11
+			}
2e9f11
+
2e9f11
+			append_gvalue (str, value);
2e9f11
+			g_free (param_name);
2e9f11
+		} else {
2e9f11
+			g_string_append_len (str,
2e9f11
+			                     &query[start],
2e9f11
+			                     end - start);
2e9f11
+		}
2e9f11
+
2e9f11
+		g_string_append_c (str, ' ');
2e9f11
+	}
2e9f11
+
2e9f11
+	return g_string_free (str, FALSE);
2e9f11
+}
2e9f11
+
2e9f11
+static TrackerSparqlCursor *
2e9f11
+execute_statement (TrackerSparqlStatement  *stmt,
2e9f11
+                   GHashTable              *bindings,
2e9f11
+                   GCancellable            *cancellable,
2e9f11
+                   GError                 **error)
2e9f11
+{
2e9f11
+	TrackerSparqlCursor *cursor;
2e9f11
+	gchar *rewritten_query = NULL;
2e9f11
+
2e9f11
+	if (g_hash_table_size (bindings) > 0) {
2e9f11
+		rewritten_query = apply_bindings (stmt, bindings, error);
2e9f11
+		if (!rewritten_query)
2e9f11
+			return NULL;
2e9f11
+	}
2e9f11
+
2e9f11
+	cursor = tracker_sparql_connection_query (tracker_sparql_statement_get_connection (stmt),
2e9f11
+	                                          rewritten_query ? rewritten_query :
2e9f11
+	                                          tracker_sparql_statement_get_sparql (stmt),
2e9f11
+	                                          cancellable,
2e9f11
+	                                          error);
2e9f11
+	g_free (rewritten_query);
2e9f11
+
2e9f11
+	return cursor;
2e9f11
+}
2e9f11
+
2e9f11
+TrackerSparqlCursor *
2e9f11
+tracker_remote_statement_execute (TrackerSparqlStatement  *stmt,
2e9f11
+                                  GCancellable            *cancellable,
2e9f11
+                                  GError                 **error)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+
2e9f11
+	return execute_statement (stmt, remote_stmt->bindings, cancellable, error);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+execute_in_thread (GTask        *task,
2e9f11
+                   gpointer      object,
2e9f11
+                   gpointer      task_data,
2e9f11
+                   GCancellable *cancellable)
2e9f11
+{
2e9f11
+	TrackerSparqlCursor *cursor;
2e9f11
+	GHashTable *bindings = task_data;
2e9f11
+	GError *error = NULL;
2e9f11
+
2e9f11
+	if (g_task_return_error_if_cancelled (task))
2e9f11
+		return;
2e9f11
+
2e9f11
+	cursor = execute_statement (object,
2e9f11
+	                            bindings,
2e9f11
+	                            g_task_get_cancellable (task),
2e9f11
+	                            &error);
2e9f11
+	if (error)
2e9f11
+		g_task_return_error (task, error);
2e9f11
+	else
2e9f11
+		g_task_return_pointer (task, cursor, g_object_unref);
2e9f11
+
2e9f11
+	g_object_unref (task);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+free_gvalue (gpointer data)
2e9f11
+{
2e9f11
+	g_value_unset (data);
2e9f11
+	g_free (data);
2e9f11
+}
2e9f11
+
2e9f11
+static GHashTable *
2e9f11
+create_bindings_ht (void)
2e9f11
+{
2e9f11
+	return g_hash_table_new_full (g_str_hash, g_str_equal,
2e9f11
+				      g_free, free_gvalue);
2e9f11
+}
2e9f11
+
2e9f11
+static GHashTable *
2e9f11
+copy_values_deep (GHashTable *values)
2e9f11
+{
2e9f11
+	GHashTable *copy;
2e9f11
+	GHashTableIter iter;
2e9f11
+	gpointer key, val;
2e9f11
+
2e9f11
+	copy = create_bindings_ht ();
2e9f11
+	g_hash_table_iter_init (&iter, values);
2e9f11
+
2e9f11
+	while (g_hash_table_iter_next (&iter, &key, &val)) {
2e9f11
+		GValue *copy_value;
2e9f11
+
2e9f11
+		copy_value = g_new0 (GValue, 1);
2e9f11
+		g_value_init (copy_value, G_VALUE_TYPE (val));
2e9f11
+		g_value_copy (val, copy_value);
2e9f11
+
2e9f11
+		g_hash_table_insert (copy, g_strdup (key), copy_value);
2e9f11
+	}
2e9f11
+
2e9f11
+	return copy;
2e9f11
+}
2e9f11
+
2e9f11
+void
2e9f11
+tracker_remote_statement_execute_async (TrackerSparqlStatement *stmt,
2e9f11
+                                        GCancellable           *cancellable,
2e9f11
+                                        GAsyncReadyCallback     callback,
2e9f11
+                                        gpointer                user_data)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	GHashTable *bindings;
2e9f11
+	GTask *task;
2e9f11
+
2e9f11
+	bindings = copy_values_deep (remote_stmt->bindings);
2e9f11
+
2e9f11
+	task = g_task_new (stmt, cancellable, callback, user_data);
2e9f11
+	g_task_set_task_data (task, bindings, (GDestroyNotify) g_hash_table_unref);
2e9f11
+	g_task_run_in_thread (task, execute_in_thread);
2e9f11
+}
2e9f11
+
2e9f11
+TrackerSparqlCursor *
2e9f11
+tracker_remote_statement_execute_finish (TrackerSparqlStatement  *stmt,
2e9f11
+                                         GAsyncResult            *res,
2e9f11
+                                         GError                 **error)
2e9f11
+{
2e9f11
+	return g_task_propagate_pointer (G_TASK (res), error);
2e9f11
+}
2e9f11
+
2e9f11
+void
2e9f11
+tracker_remote_statement_clear_bindings (TrackerSparqlStatement *stmt)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+
2e9f11
+	g_hash_table_remove_all (remote_stmt->bindings);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_class_init (TrackerRemoteStatementClass *klass)
2e9f11
+{
2e9f11
+	TrackerSparqlStatementClass *stmt_class = TRACKER_SPARQL_STATEMENT_CLASS (klass);
2e9f11
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
2e9f11
+
2e9f11
+	object_class->finalize = tracker_remote_statement_finalize;
2e9f11
+
2e9f11
+	stmt_class->bind_int = tracker_remote_statement_bind_int;
2e9f11
+	stmt_class->bind_boolean = tracker_remote_statement_bind_boolean;
2e9f11
+	stmt_class->bind_string = tracker_remote_statement_bind_string;
2e9f11
+	stmt_class->bind_double = tracker_remote_statement_bind_double;
2e9f11
+	stmt_class->execute = tracker_remote_statement_execute;
2e9f11
+	stmt_class->execute_async = tracker_remote_statement_execute_async;
2e9f11
+	stmt_class->execute_finish = tracker_remote_statement_execute_finish;
2e9f11
+	stmt_class->clear_bindings = tracker_remote_statement_clear_bindings;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_remote_statement_init (TrackerRemoteStatement *stmt)
2e9f11
+{
2e9f11
+	stmt->bindings = create_bindings_ht ();
2e9f11
+}
2e9f11
+
2e9f11
+TrackerSparqlStatement *
2e9f11
+tracker_remote_statement_new (TrackerSparqlConnection  *conn,
2e9f11
+                              const gchar              *query,
2e9f11
+                              GError                  **error)
2e9f11
+{
2e9f11
+	TrackerRemoteStatement *remote_stmt;
2e9f11
+	TrackerSparqlStatement *stmt;
2e9f11
+
2e9f11
+	stmt = g_object_new (TRACKER_TYPE_REMOTE_STATEMENT,
2e9f11
+	                            "connection", conn,
2e9f11
+	                            "sparql", query,
2e9f11
+	                            NULL);
2e9f11
+	remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
+	remote_stmt->parser_tree =
2e9f11
+		tracker_sparql_parse_query (tracker_sparql_statement_get_sparql (stmt),
2e9f11
+		                            -1, NULL, error);
2e9f11
+	if (!remote_stmt->parser_tree) {
2e9f11
+		g_object_unref (stmt);
2e9f11
+		return NULL;
2e9f11
+	}
2e9f11
+
2e9f11
+	return stmt;
2e9f11
+}
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote-statement.h b/src/libtracker-sparql/remote/tracker-remote-statement.h
2e9f11
new file mode 100644
2e9f11
index 000000000..1cedf3811
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote-statement.h
2e9f11
@@ -0,0 +1,32 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2021, Red Hat Ltd.
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#include <libtracker-sparql/tracker-private.h>
2e9f11
+
2e9f11
+#define TRACKER_TYPE_REMOTE_STATEMENT (tracker_remote_statement_get_type ())
2e9f11
+G_DECLARE_FINAL_TYPE (TrackerRemoteStatement,
2e9f11
+                      tracker_remote_statement,
2e9f11
+                      TRACKER, REMOTE_STATEMENT,
2e9f11
+                      TrackerSparqlStatement)
2e9f11
+
2e9f11
+TrackerSparqlStatement * tracker_remote_statement_new (TrackerSparqlConnection  *conn,
2e9f11
+                                                       const gchar              *query,
2e9f11
+                                                       GError                  **error);
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vala b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
index f29a989ad..f3be3147a 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
@@ -110,6 +110,10 @@ public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
 #endif
2e9f11
 	}
2e9f11
 
2e9f11
+	public override Sparql.Statement? query_statement (string sparql, GLib.Cancellable? cancellable = null) throws Sparql.Error {
2e9f11
+		return new Remote.Statement (this, sparql);
2e9f11
+	}
2e9f11
+
2e9f11
 	public override void close () {
2e9f11
 	}
2e9f11
 
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vapi b/src/libtracker-sparql/remote/tracker-remote.vapi
2e9f11
new file mode 100644
2e9f11
index 000000000..caf018b41
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vapi
2e9f11
@@ -0,0 +1,6 @@
2e9f11
+namespace Tracker {
2e9f11
+	[CCode (cheader_filename = "libtracker-sparql/remote/tracker-remote-statement.h")]
2e9f11
+	class Remote.Statement : Sparql.Statement {
2e9f11
+		public Statement (Sparql.Connection conn, string query) throws Sparql.Error;
2e9f11
+	}
2e9f11
+}
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 04f2b77b5c1958db2c2de6d54d716ef20c0b59dc Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Sat, 27 Nov 2021 14:54:51 +0100
2e9f11
Subject: [PATCH 06/11] libtracker-sparql: Add missing "static" in functions
2e9f11
2e9f11
Luckily, these symbols won't be leaked, still not great.
2e9f11
---
2e9f11
 src/libtracker-sparql/remote/tracker-remote-statement.c | 6 +++---
2e9f11
 1 file changed, 3 insertions(+), 3 deletions(-)
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote-statement.c b/src/libtracker-sparql/remote/tracker-remote-statement.c
2e9f11
index 6ca9f5246..ad80a589b 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote-statement.c
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote-statement.c
2e9f11
@@ -319,7 +319,7 @@ copy_values_deep (GHashTable *values)
2e9f11
 	return copy;
2e9f11
 }
2e9f11
 
2e9f11
-void
2e9f11
+static void
2e9f11
 tracker_remote_statement_execute_async (TrackerSparqlStatement *stmt,
2e9f11
                                         GCancellable           *cancellable,
2e9f11
                                         GAsyncReadyCallback     callback,
2e9f11
@@ -336,7 +336,7 @@ tracker_remote_statement_execute_async (TrackerSparqlStatement *stmt,
2e9f11
 	g_task_run_in_thread (task, execute_in_thread);
2e9f11
 }
2e9f11
 
2e9f11
-TrackerSparqlCursor *
2e9f11
+static TrackerSparqlCursor *
2e9f11
 tracker_remote_statement_execute_finish (TrackerSparqlStatement  *stmt,
2e9f11
                                          GAsyncResult            *res,
2e9f11
                                          GError                 **error)
2e9f11
@@ -344,7 +344,7 @@ tracker_remote_statement_execute_finish (TrackerSparqlStatement  *stmt,
2e9f11
 	return g_task_propagate_pointer (G_TASK (res), error);
2e9f11
 }
2e9f11
 
2e9f11
-void
2e9f11
+static void
2e9f11
 tracker_remote_statement_clear_bindings (TrackerSparqlStatement *stmt)
2e9f11
 {
2e9f11
 	TrackerRemoteStatement *remote_stmt = TRACKER_REMOTE_STATEMENT (stmt);
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 663e1784cfaab1d00eaf1c30e6549faa52e2f96f Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Sat, 23 Apr 2022 13:22:54 +0200
2e9f11
Subject: [PATCH 07/11] libtracker-sparql: Move TrackerSerializerFormat enum to
2e9f11
 distinct header
2e9f11
2e9f11
We want this enum to be used from places that do not necessarily pull
2e9f11
TrackerSerializer directly, or other internals. Move it to a separate
2e9f11
header so that the enum can be used without further dependencies.
2e9f11
---
2e9f11
 src/libtracker-sparql/tracker-enums-private.h | 32 +++++++++++++++++++
2e9f11
 src/libtracker-sparql/tracker-private.h       |  1 +
2e9f11
 src/libtracker-sparql/tracker-serializer.h    |  7 +---
2e9f11
 3 files changed, 34 insertions(+), 6 deletions(-)
2e9f11
 create mode 100644 src/libtracker-sparql/tracker-enums-private.h
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/tracker-enums-private.h b/src/libtracker-sparql/tracker-enums-private.h
2e9f11
new file mode 100644
2e9f11
index 000000000..1d193b277
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/tracker-enums-private.h
2e9f11
@@ -0,0 +1,32 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2022, Red Hat, Inc
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#ifndef TRACKER_ENUMS_PRIVATE_H
2e9f11
+#define TRACKER_ENUMS_PRIVATE_H
2e9f11
+
2e9f11
+typedef enum
2e9f11
+{
2e9f11
+	TRACKER_SERIALIZER_FORMAT_JSON, /* application/sparql-results+json */
2e9f11
+	TRACKER_SERIALIZER_FORMAT_XML, /* application/sparql-results+xml */
2e9f11
+	TRACKER_N_SERIALIZER_FORMATS
2e9f11
+} TrackerSerializerFormat;
2e9f11
+
2e9f11
+#endif /* TRACKER_ENUMS_PRIVATE_H */
2e9f11
diff --git a/src/libtracker-sparql/tracker-private.h b/src/libtracker-sparql/tracker-private.h
2e9f11
index b8c6381ec..c95568b45 100644
2e9f11
--- a/src/libtracker-sparql/tracker-private.h
2e9f11
+++ b/src/libtracker-sparql/tracker-private.h
2e9f11
@@ -23,6 +23,7 @@
2e9f11
 #include <libtracker-sparql/tracker-version-generated.h>
2e9f11
 #include <libtracker-sparql/tracker-cursor.h>
2e9f11
 #include <libtracker-sparql/tracker-endpoint-dbus.h>
2e9f11
+#include <libtracker-sparql/tracker-enums-private.h>
2e9f11
 
2e9f11
 typedef struct _TrackerSparqlConnectionClass TrackerSparqlConnectionClass;
2e9f11
 
2e9f11
diff --git a/src/libtracker-sparql/tracker-serializer.h b/src/libtracker-sparql/tracker-serializer.h
2e9f11
index f948858bb..704fea06a 100644
2e9f11
--- a/src/libtracker-sparql/tracker-serializer.h
2e9f11
+++ b/src/libtracker-sparql/tracker-serializer.h
2e9f11
@@ -23,6 +23,7 @@
2e9f11
 #define TRACKER_SERIALIZER_H
2e9f11
 
2e9f11
 #include <libtracker-sparql/tracker-sparql.h>
2e9f11
+#include <libtracker-sparql/tracker-enums-private.h>
2e9f11
 
2e9f11
 #define TRACKER_TYPE_SERIALIZER (tracker_serializer_get_type())
2e9f11
 
2e9f11
@@ -31,12 +32,6 @@ G_DECLARE_DERIVABLE_TYPE (TrackerSerializer,
2e9f11
                           TRACKER, SERIALIZER,
2e9f11
                           GInputStream);
2e9f11
 
2e9f11
-typedef enum
2e9f11
-{
2e9f11
-	TRACKER_SERIALIZER_FORMAT_JSON, /* application/sparql-results+json */
2e9f11
-	TRACKER_SERIALIZER_FORMAT_XML, /* application/sparql-results+xml */
2e9f11
-} TrackerSerializerFormat;
2e9f11
-
2e9f11
 GInputStream * tracker_serializer_new (TrackerSparqlCursor     *cursor,
2e9f11
                                        TrackerSerializerFormat  format);
2e9f11
 
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 477bc7f3bcabf213d3887e5d6312ef02e1025b01 Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Sat, 23 Apr 2022 13:41:06 +0200
2e9f11
Subject: [PATCH 08/11] libtracker-sparql: Add base http helper object
2e9f11
 definitions
2e9f11
2e9f11
This is a small internal API consisting of a TrackerHttpClient and
2e9f11
a TrackerHttpServer abstract objects. These are meant to wrap the
2e9f11
interaction with libsoup in a way that is most isolated from internal
2e9f11
library workings.
2e9f11
2e9f11
These objects will have final implementations living in modules, but
2e9f11
also will be interacted through the base API from the library code,
2e9f11
this so far adds the latter.
2e9f11
---
2e9f11
 src/libtracker-sparql/meson.build           |   3 +
2e9f11
 src/libtracker-sparql/remote/meson.build    |   3 +
2e9f11
 src/libtracker-sparql/remote/tracker-http.c | 334 ++++++++++++++++++++
2e9f11
 src/libtracker-sparql/remote/tracker-http.h | 122 +++++++
2e9f11
 4 files changed, 462 insertions(+)
2e9f11
 create mode 100644 src/libtracker-sparql/remote/meson.build
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-http.c
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-http.h
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
2e9f11
index 21b9b5a28..c1ba14a83 100644
2e9f11
--- a/src/libtracker-sparql/meson.build
2e9f11
+++ b/src/libtracker-sparql/meson.build
2e9f11
@@ -1,3 +1,5 @@
2e9f11
+subdir('remote')
2e9f11
+
2e9f11
 version_header = configure_file(
2e9f11
     input: 'tracker-version-generated.h.meson.in',
2e9f11
     output: 'tracker-version-generated.h',
2e9f11
@@ -148,6 +150,7 @@ libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
2e9f11
     'direct/tracker-direct.vapi',
2e9f11
     'tracker-backend.vala',
2e9f11
     'tracker-remote-module.c',
2e9f11
+    remote_files,
2e9f11
     tracker_gresources,
2e9f11
 
2e9f11
     gnu_symbol_visibility: 'hidden',
2e9f11
diff --git a/src/libtracker-sparql/remote/meson.build b/src/libtracker-sparql/remote/meson.build
2e9f11
new file mode 100644
2e9f11
index 000000000..5cc639795
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/meson.build
2e9f11
@@ -0,0 +1,3 @@
2e9f11
+remote_files = files(
2e9f11
+    'tracker-http.c',
2e9f11
+)
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-http.c b/src/libtracker-sparql/remote/tracker-http.c
2e9f11
new file mode 100644
2e9f11
index 000000000..345f8412d
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-http.c
2e9f11
@@ -0,0 +1,334 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2022, Red Hat Inc.
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#include "config.h"
2e9f11
+
2e9f11
+#include <gio/gio.h>
2e9f11
+#include <tracker-sparql.h>
2e9f11
+#include <dlfcn.h>
2e9f11
+
2e9f11
+#include "tracker-http.h"
2e9f11
+
2e9f11
+static GType client_type = G_TYPE_NONE;
2e9f11
+static GType server_type = G_TYPE_NONE;
2e9f11
+
2e9f11
+/* Module loading */
2e9f11
+#define LIBSOUP_2_SONAME "libsoup-2.4.so.1"
2e9f11
+
2e9f11
+static void
2e9f11
+ensure_types (void)
2e9f11
+{
2e9f11
+	const char *modules[3] = { 0 };
2e9f11
+	gpointer handle = NULL;
2e9f11
+	gint i = 0;
2e9f11
+
2e9f11
+	if (client_type != G_TYPE_NONE)
2e9f11
+		return;
2e9f11
+
2e9f11
+	g_assert (g_module_supported ());
2e9f11
+
2e9f11
+#ifdef HAVE_RTLD_NOLOAD
2e9f11
+	if ((handle = dlopen (LIBSOUP_2_SONAME, RTLD_NOW | RTLD_NOLOAD))) {
2e9f11
+		/* Force load of soup2 module */
2e9f11
+		modules[0] = "libtracker-http-soup2.so";
2e9f11
+	} else
2e9f11
+#endif
2e9f11
+	{
2e9f11
+		modules[0] = "libtracker-http-soup3.so";
2e9f11
+		modules[1] = "libtracker-http-soup2.so";
2e9f11
+	}
2e9f11
+
2e9f11
+	g_clear_pointer (&handle, dlclose);
2e9f11
+
2e9f11
+	for (i = 0; modules[i]; i++) {
2e9f11
+		GModule *remote_module;
2e9f11
+		gchar *module_path;
2e9f11
+		void (* init_func) (GType *client, GType *server);
2e9f11
+
2e9f11
+		if (g_strcmp0 (g_get_current_dir (), BUILDROOT) == 0) {
2e9f11
+			/* Detect in-build runtime of this code, this may happen
2e9f11
+			 * building introspection information or running tests.
2e9f11
+			 * We want the in-tree modules to be loaded then.
2e9f11
+			 */
2e9f11
+			module_path = g_strdup_printf (BUILD_LIBDIR "/remote/%s", modules[i]);
2e9f11
+		} else {
2e9f11
+			module_path = g_strdup_printf (PRIVATE_LIBDIR "/%s", modules[i]);
2e9f11
+		}
2e9f11
+
2e9f11
+		if (!g_file_test (module_path, G_FILE_TEST_EXISTS)) {
2e9f11
+			g_free (module_path);
2e9f11
+			continue;
2e9f11
+		}
2e9f11
+
2e9f11
+		remote_module = g_module_open (module_path,
2e9f11
+		                               G_MODULE_BIND_LAZY |
2e9f11
+		                               G_MODULE_BIND_LOCAL);
2e9f11
+		g_free (module_path);
2e9f11
+
2e9f11
+		if (!remote_module) {
2e9f11
+			g_printerr ("Could not load '%s': %s\n",
2e9f11
+			            modules[i], g_module_error ());
2e9f11
+			continue;
2e9f11
+		}
2e9f11
+
2e9f11
+		if (!g_module_symbol (remote_module, "initialize_types", (gpointer *) &init_func)) {
2e9f11
+			g_printerr ("Could find init function: %s\n",
2e9f11
+			            g_module_error ());
2e9f11
+			g_clear_pointer (&remote_module, g_module_close);
2e9f11
+			continue;
2e9f11
+		}
2e9f11
+
2e9f11
+		g_type_ensure (TRACKER_TYPE_HTTP_CLIENT);
2e9f11
+		g_type_ensure (TRACKER_TYPE_HTTP_SERVER);
2e9f11
+
2e9f11
+		init_func (&client_type, &server_type);
2e9f11
+
2e9f11
+		g_module_make_resident (remote_module);
2e9f11
+		g_module_close (remote_module);
2e9f11
+
2e9f11
+		g_assert (client_type != G_TYPE_NONE);
2e9f11
+		g_assert (server_type != G_TYPE_NONE);
2e9f11
+		return;
2e9f11
+	}
2e9f11
+
2e9f11
+	g_assert_not_reached ();
2e9f11
+}
2e9f11
+
2e9f11
+/* HTTP server */
2e9f11
+enum {
2e9f11
+	PROP_0,
2e9f11
+	PROP_HTTP_PORT,
2e9f11
+	PROP_HTTP_CERTIFICATE,
2e9f11
+	N_SERVER_PROPS
2e9f11
+};
2e9f11
+
2e9f11
+enum {
2e9f11
+	REQUEST,
2e9f11
+	N_SERVER_SIGNALS,
2e9f11
+};
2e9f11
+
2e9f11
+typedef struct
2e9f11
+{
2e9f11
+	guint port;
2e9f11
+	GTlsCertificate *certificate;
2e9f11
+} TrackerHttpServerPrivate;
2e9f11
+
2e9f11
+static GParamSpec *server_props[N_SERVER_PROPS] = { 0 };
2e9f11
+static guint server_signals[N_SERVER_SIGNALS] = { 0 };
2e9f11
+
2e9f11
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (TrackerHttpServer,
2e9f11
+                                     tracker_http_server,
2e9f11
+                                     G_TYPE_OBJECT)
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_set_property (GObject      *object,
2e9f11
+                                  guint         prop_id,
2e9f11
+                                  const GValue *value,
2e9f11
+                                  GParamSpec   *pspec)
2e9f11
+{
2e9f11
+	TrackerHttpServer *server = TRACKER_HTTP_SERVER (object);
2e9f11
+	TrackerHttpServerPrivate *priv =
2e9f11
+		tracker_http_server_get_instance_private (server);
2e9f11
+
2e9f11
+	switch (prop_id) {
2e9f11
+	case PROP_HTTP_PORT:
2e9f11
+		priv->port = g_value_get_uint (value);
2e9f11
+		break;
2e9f11
+	case PROP_HTTP_CERTIFICATE:
2e9f11
+		priv->certificate = g_value_dup_object (value);
2e9f11
+		break;
2e9f11
+	default:
2e9f11
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2e9f11
+	}
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_get_property (GObject    *object,
2e9f11
+                                  guint       prop_id,
2e9f11
+                                  GValue     *value,
2e9f11
+                                  GParamSpec *pspec)
2e9f11
+{
2e9f11
+	TrackerHttpServer *server = TRACKER_HTTP_SERVER (object);
2e9f11
+	TrackerHttpServerPrivate *priv =
2e9f11
+		tracker_http_server_get_instance_private (server);
2e9f11
+
2e9f11
+	switch (prop_id) {
2e9f11
+	case PROP_HTTP_PORT:
2e9f11
+		g_value_set_uint (value, priv->port);
2e9f11
+		break;
2e9f11
+	case PROP_HTTP_CERTIFICATE:
2e9f11
+		g_value_set_object (value, priv->certificate);
2e9f11
+		break;
2e9f11
+	default:
2e9f11
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2e9f11
+	}
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_class_init (TrackerHttpServerClass *klass)
2e9f11
+{
2e9f11
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
2e9f11
+
2e9f11
+	object_class->set_property = tracker_http_server_set_property;
2e9f11
+	object_class->get_property = tracker_http_server_get_property;
2e9f11
+
2e9f11
+	server_signals[REQUEST] =
2e9f11
+		g_signal_new ("request",
2e9f11
+		              TRACKER_TYPE_HTTP_SERVER, 0, 0,
2e9f11
+		              NULL, NULL, NULL,
2e9f11
+		              G_TYPE_NONE, 5,
2e9f11
+		              G_TYPE_SOCKET_ADDRESS,
2e9f11
+		              G_TYPE_STRING,
2e9f11
+		              G_TYPE_HASH_TABLE,
2e9f11
+		              G_TYPE_UINT,
2e9f11
+		              G_TYPE_POINTER);
2e9f11
+
2e9f11
+	server_props[PROP_HTTP_PORT] =
2e9f11
+		g_param_spec_uint ("http-port",
2e9f11
+		                   "HTTP Port",
2e9f11
+		                   "HTTP Port",
2e9f11
+		                   0, G_MAXUINT,
2e9f11
+		                   8080,
2e9f11
+		                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
2e9f11
+	server_props[PROP_HTTP_CERTIFICATE] =
2e9f11
+		g_param_spec_object ("http-certificate",
2e9f11
+		                     "HTTP certificate",
2e9f11
+		                     "HTTP certificate",
2e9f11
+		                     G_TYPE_TLS_CERTIFICATE,
2e9f11
+		                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
2e9f11
+
2e9f11
+	g_object_class_install_properties (object_class,
2e9f11
+	                                   N_SERVER_PROPS,
2e9f11
+	                                   server_props);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_init (TrackerHttpServer *server)
2e9f11
+{
2e9f11
+}
2e9f11
+
2e9f11
+TrackerHttpServer *
2e9f11
+tracker_http_server_new (guint             port,
2e9f11
+                         GTlsCertificate  *certificate,
2e9f11
+                         GCancellable     *cancellable,
2e9f11
+                         GError          **error)
2e9f11
+{
2e9f11
+	ensure_types ();
2e9f11
+
2e9f11
+	return g_initable_new (server_type,
2e9f11
+	                       cancellable, error,
2e9f11
+	                       "http-port", port,
2e9f11
+	                       "http-certificate", certificate,
2e9f11
+	                       NULL);
2e9f11
+}
2e9f11
+
2e9f11
+void
2e9f11
+tracker_http_server_response (TrackerHttpServer       *server,
2e9f11
+                              TrackerHttpRequest      *request,
2e9f11
+                              TrackerSerializerFormat  format,
2e9f11
+                              GInputStream            *content)
2e9f11
+{
2e9f11
+	TRACKER_HTTP_SERVER_GET_CLASS (server)->response (server,
2e9f11
+	                                                  request,
2e9f11
+	                                                  format,
2e9f11
+	                                                  content);
2e9f11
+}
2e9f11
+
2e9f11
+void
2e9f11
+tracker_http_server_error (TrackerHttpServer  *server,
2e9f11
+                           TrackerHttpRequest *request,
2e9f11
+                           gint                code,
2e9f11
+                           const gchar        *message)
2e9f11
+{
2e9f11
+	TRACKER_HTTP_SERVER_GET_CLASS (server)->error (server,
2e9f11
+	                                               request,
2e9f11
+	                                               code,
2e9f11
+	                                               message);
2e9f11
+}
2e9f11
+
2e9f11
+/* HTTP client */
2e9f11
+G_DEFINE_ABSTRACT_TYPE (TrackerHttpClient, tracker_http_client, G_TYPE_OBJECT)
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_client_class_init (TrackerHttpClientClass *klass)
2e9f11
+{
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_client_init (TrackerHttpClient *server)
2e9f11
+{
2e9f11
+}
2e9f11
+
2e9f11
+TrackerHttpClient *
2e9f11
+tracker_http_client_new (void)
2e9f11
+{
2e9f11
+	ensure_types ();
2e9f11
+
2e9f11
+	return g_object_new (client_type, NULL);
2e9f11
+}
2e9f11
+
2e9f11
+void
2e9f11
+tracker_http_client_send_message_async (TrackerHttpClient   *client,
2e9f11
+                                        const gchar         *uri,
2e9f11
+                                        const gchar         *query,
2e9f11
+                                        guint                formats,
2e9f11
+                                        GCancellable        *cancellable,
2e9f11
+                                        GAsyncReadyCallback  callback,
2e9f11
+                                        gpointer             user_data)
2e9f11
+{
2e9f11
+	TRACKER_HTTP_CLIENT_GET_CLASS (client)->send_message_async (client,
2e9f11
+	                                                            uri,
2e9f11
+	                                                            query,
2e9f11
+	                                                            formats,
2e9f11
+	                                                            cancellable,
2e9f11
+	                                                            callback,
2e9f11
+	                                                            user_data);
2e9f11
+}
2e9f11
+
2e9f11
+GInputStream *
2e9f11
+tracker_http_client_send_message_finish (TrackerHttpClient        *client,
2e9f11
+                                         GAsyncResult             *res,
2e9f11
+                                         TrackerSerializerFormat  *format,
2e9f11
+                                         GError                  **error)
2e9f11
+{
2e9f11
+	return TRACKER_HTTP_CLIENT_GET_CLASS (client)->send_message_finish (client,
2e9f11
+	                                                                    res,
2e9f11
+	                                                                    format,
2e9f11
+	                                                                    error);
2e9f11
+}
2e9f11
+
2e9f11
+GInputStream *
2e9f11
+tracker_http_client_send_message (TrackerHttpClient        *client,
2e9f11
+                                  const gchar              *uri,
2e9f11
+                                  const gchar              *query,
2e9f11
+                                  guint                     formats,
2e9f11
+                                  GCancellable             *cancellable,
2e9f11
+                                  TrackerSerializerFormat  *format,
2e9f11
+                                  GError                  **error)
2e9f11
+{
2e9f11
+	return TRACKER_HTTP_CLIENT_GET_CLASS (client)->send_message (client,
2e9f11
+	                                                             uri,
2e9f11
+	                                                             query,
2e9f11
+	                                                             formats,
2e9f11
+	                                                             cancellable,
2e9f11
+	                                                             format,
2e9f11
+	                                                             error);
2e9f11
+}
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-http.h b/src/libtracker-sparql/remote/tracker-http.h
2e9f11
new file mode 100644
2e9f11
index 000000000..15e3498c0
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-http.h
2e9f11
@@ -0,0 +1,122 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2022, Red Hat Inc.
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#ifndef TRACKER_HTTP_H
2e9f11
+#define TRACKER_HTTP_H
2e9f11
+
2e9f11
+#include <gio/gio.h>
2e9f11
+
2e9f11
+#ifndef MODULE
2e9f11
+#include <libtracker-sparql/tracker-enums-private.h>
2e9f11
+#endif
2e9f11
+
2e9f11
+typedef struct _TrackerHttpRequest TrackerHttpRequest;
2e9f11
+
2e9f11
+#define TRACKER_TYPE_HTTP_SERVER (tracker_http_server_get_type ())
2e9f11
+G_DECLARE_DERIVABLE_TYPE (TrackerHttpServer,
2e9f11
+                          tracker_http_server,
2e9f11
+                          TRACKER, HTTP_SERVER,
2e9f11
+                          GObject)
2e9f11
+
2e9f11
+struct _TrackerHttpServerClass {
2e9f11
+	GObjectClass parent_class;
2e9f11
+
2e9f11
+	void (* response) (TrackerHttpServer       *server,
2e9f11
+	                   TrackerHttpRequest      *request,
2e9f11
+	                   TrackerSerializerFormat  format,
2e9f11
+	                   GInputStream            *content);
2e9f11
+	void (* error) (TrackerHttpServer  *server,
2e9f11
+	                TrackerHttpRequest *request,
2e9f11
+	                gint                code,
2e9f11
+	                const gchar        *message);
2e9f11
+};
2e9f11
+
2e9f11
+TrackerHttpServer * tracker_http_server_new (guint             port,
2e9f11
+                                             GTlsCertificate  *certificate,
2e9f11
+                                             GCancellable     *cancellable,
2e9f11
+                                             GError          **error);
2e9f11
+
2e9f11
+void tracker_http_server_response (TrackerHttpServer       *server,
2e9f11
+                                   TrackerHttpRequest      *request,
2e9f11
+                                   TrackerSerializerFormat  format,
2e9f11
+                                   GInputStream            *content);
2e9f11
+
2e9f11
+void tracker_http_server_error (TrackerHttpServer       *server,
2e9f11
+                                TrackerHttpRequest      *request,
2e9f11
+                                gint                     code,
2e9f11
+                                const gchar             *message);
2e9f11
+
2e9f11
+#define TRACKER_TYPE_HTTP_CLIENT (tracker_http_client_get_type ())
2e9f11
+G_DECLARE_DERIVABLE_TYPE (TrackerHttpClient,
2e9f11
+                          tracker_http_client,
2e9f11
+                          TRACKER, HTTP_CLIENT,
2e9f11
+                          GObject)
2e9f11
+
2e9f11
+struct _TrackerHttpClientClass {
2e9f11
+	GObjectClass parent_class;
2e9f11
+
2e9f11
+	void (* send_message_async) (TrackerHttpClient   *client,
2e9f11
+	                             const gchar         *uri,
2e9f11
+	                             const gchar         *query,
2e9f11
+	                             guint                formats,
2e9f11
+	                             GCancellable        *cancellable,
2e9f11
+	                             GAsyncReadyCallback  callback,
2e9f11
+	                             gpointer             user_data);
2e9f11
+	GInputStream * (* send_message_finish) (TrackerHttpClient        *client,
2e9f11
+	                                        GAsyncResult             *res,
2e9f11
+	                                        TrackerSerializerFormat  *format,
2e9f11
+	                                        GError                  **error);
2e9f11
+	GInputStream * (* send_message) (TrackerHttpClient        *client,
2e9f11
+	                                 const gchar              *uri,
2e9f11
+	                                 const gchar              *query,
2e9f11
+	                                 guint                     formats,
2e9f11
+	                                 GCancellable             *cancellable,
2e9f11
+	                                 TrackerSerializerFormat  *format,
2e9f11
+	                                 GError                  **error);
2e9f11
+};
2e9f11
+
2e9f11
+TrackerHttpClient * tracker_http_client_new (void);
2e9f11
+
2e9f11
+GInputStream *
2e9f11
+tracker_http_client_send_message (TrackerHttpClient        *client,
2e9f11
+                                  const gchar              *uri,
2e9f11
+                                  const gchar              *query,
2e9f11
+                                  guint                     formats,
2e9f11
+                                  GCancellable             *cancellable,
2e9f11
+                                  TrackerSerializerFormat  *format,
2e9f11
+                                  GError                  **error);
2e9f11
+
2e9f11
+void
2e9f11
+tracker_http_client_send_message_async (TrackerHttpClient   *client,
2e9f11
+                                        const gchar         *uri,
2e9f11
+                                        const gchar         *query,
2e9f11
+                                        guint                formats,
2e9f11
+                                        GCancellable        *cancellable,
2e9f11
+                                        GAsyncReadyCallback  callback,
2e9f11
+                                        gpointer             user_data);
2e9f11
+
2e9f11
+GInputStream *
2e9f11
+tracker_http_client_send_message_finish (TrackerHttpClient        *client,
2e9f11
+                                         GAsyncResult             *res,
2e9f11
+                                         TrackerSerializerFormat  *format,
2e9f11
+                                         GError                  **error);
2e9f11
+
2e9f11
+#endif /* TRACKER_HTTP_H */
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From eacc6ab2ca3177f593983133e0664d6b11a16978 Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Sat, 23 Apr 2022 13:49:44 +0200
2e9f11
Subject: [PATCH 09/11] libtracker-sparql: Add HTTP module soup2/soup3
2e9f11
 implementation
2e9f11
2e9f11
These modules implement TrackerHttpClient and TrackerHttpServer using
2e9f11
the 2 relevant major libsoup versions. These modules are built and
2e9f11
installed, but dormant and unused.
2e9f11
---
2e9f11
 src/libtracker-sparql/meson.build             |   2 +
2e9f11
 src/libtracker-sparql/remote/meson.build      |  34 ++
2e9f11
 .../remote/tracker-http-module.c              | 564 ++++++++++++++++++
2e9f11
 .../remote/tracker-http-module.h              |  39 ++
2e9f11
 4 files changed, 639 insertions(+)
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-http-module.c
2e9f11
 create mode 100644 src/libtracker-sparql/remote/tracker-http-module.h
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
2e9f11
index c1ba14a83..2cc0eebab 100644
2e9f11
--- a/src/libtracker-sparql/meson.build
2e9f11
+++ b/src/libtracker-sparql/meson.build
2e9f11
@@ -1,3 +1,5 @@
2e9f11
+libtracker_sparql_modules = []
2e9f11
+
2e9f11
 subdir('remote')
2e9f11
 
2e9f11
 version_header = configure_file(
2e9f11
diff --git a/src/libtracker-sparql/remote/meson.build b/src/libtracker-sparql/remote/meson.build
2e9f11
index 5cc639795..ca137b85e 100644
2e9f11
--- a/src/libtracker-sparql/remote/meson.build
2e9f11
+++ b/src/libtracker-sparql/remote/meson.build
2e9f11
@@ -1,3 +1,37 @@
2e9f11
 remote_files = files(
2e9f11
     'tracker-http.c',
2e9f11
 )
2e9f11
+
2e9f11
+module_sources = files('tracker-http-module.c')
2e9f11
+
2e9f11
+if libsoup2.found()
2e9f11
+    libtracker_http_soup2 = shared_module('tracker-http-soup2',
2e9f11
+        module_sources,
2e9f11
+        dependencies: [libsoup2],
2e9f11
+        c_args: tracker_c_args + [
2e9f11
+            '-include', 'config.h',
2e9f11
+            '-include', '../tracker-enums-private.h',
2e9f11
+            '-DMODULE',
2e9f11
+        ],
2e9f11
+        install: true,
2e9f11
+        install_dir: tracker_internal_libs_dir,
2e9f11
+        name_suffix: 'so',
2e9f11
+    )
2e9f11
+    libtracker_sparql_modules += libtracker_http_soup2
2e9f11
+endif
2e9f11
+
2e9f11
+if libsoup3.found()
2e9f11
+    libtracker_http_soup3 = shared_module('tracker-http-soup3',
2e9f11
+        module_sources,
2e9f11
+        dependencies: [libsoup3],
2e9f11
+        c_args: tracker_c_args + [
2e9f11
+            '-include', 'config.h',
2e9f11
+            '-include', '../tracker-enums-private.h',
2e9f11
+            '-DMODULE',
2e9f11
+        ],
2e9f11
+        install: true,
2e9f11
+        install_dir: tracker_internal_libs_dir,
2e9f11
+        name_suffix: 'so',
2e9f11
+    )
2e9f11
+    libtracker_sparql_modules += libtracker_http_soup3
2e9f11
+endif
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-http-module.c b/src/libtracker-sparql/remote/tracker-http-module.c
2e9f11
new file mode 100644
2e9f11
index 000000000..421005001
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-http-module.c
2e9f11
@@ -0,0 +1,564 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2022, Red Hat Inc.
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#include <libsoup/soup.h>
2e9f11
+
2e9f11
+#include "tracker-http-module.h"
2e9f11
+
2e9f11
+GType
2e9f11
+tracker_http_client_get_type (void)
2e9f11
+{
2e9f11
+	return g_type_from_name ("TrackerHttpClient");
2e9f11
+}
2e9f11
+
2e9f11
+GType
2e9f11
+tracker_http_server_get_type (void)
2e9f11
+{
2e9f11
+	return g_type_from_name ("TrackerHttpServer");
2e9f11
+}
2e9f11
+
2e9f11
+static const gchar *mimetypes[] = {
2e9f11
+	"application/sparql-results+json",
2e9f11
+	"application/sparql-results+xml",
2e9f11
+	"text/turtle",
2e9f11
+	"application/trig",
2e9f11
+};
2e9f11
+
2e9f11
+G_STATIC_ASSERT (G_N_ELEMENTS (mimetypes) == TRACKER_N_SERIALIZER_FORMATS);
2e9f11
+
2e9f11
+#define USER_AGENT "Tracker " PACKAGE_VERSION " (https://gitlab.gnome.org/GNOME/tracker/issues/)"
2e9f11
+
2e9f11
+/* Server */
2e9f11
+struct _TrackerHttpRequest
2e9f11
+{
2e9f11
+	TrackerHttpServer *server;
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        SoupServerMessage *message;
2e9f11
+#else
2e9f11
+	SoupMessage *message;
2e9f11
+#endif
2e9f11
+	GTask *task;
2e9f11
+	GInputStream *istream;
2e9f11
+};
2e9f11
+
2e9f11
+struct _TrackerHttpServerSoup
2e9f11
+{
2e9f11
+	TrackerHttpServer parent_instance;
2e9f11
+	SoupServer *server;
2e9f11
+	GCancellable *cancellable;
2e9f11
+};
2e9f11
+
2e9f11
+static void tracker_http_server_soup_initable_iface_init (GInitableIface *iface);
2e9f11
+
2e9f11
+G_DEFINE_TYPE_WITH_CODE (TrackerHttpServerSoup,
2e9f11
+                         tracker_http_server_soup,
2e9f11
+                         TRACKER_TYPE_HTTP_SERVER,
2e9f11
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
2e9f11
+                                                tracker_http_server_soup_initable_iface_init))
2e9f11
+
2e9f11
+
2e9f11
+static guint
2e9f11
+get_supported_formats (TrackerHttpRequest *request)
2e9f11
+{
2e9f11
+	SoupMessageHeaders *request_headers;
2e9f11
+	TrackerSerializerFormat i;
2e9f11
+	guint formats = 0;
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        request_headers = soup_server_message_get_request_headers (request->message);
2e9f11
+#else
2e9f11
+        request_headers = request->message->request_headers;
2e9f11
+#endif
2e9f11
+
2e9f11
+        for (i = 0; i < TRACKER_N_SERIALIZER_FORMATS; i++) {
2e9f11
+	        if (soup_message_headers_header_contains (request_headers, "Accept",
2e9f11
+	                                                  mimetypes[i]))
2e9f11
+		        formats |= 1 << i;
2e9f11
+        }
2e9f11
+
2e9f11
+	return formats;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+set_message_format (TrackerHttpRequest      *request,
2e9f11
+                    TrackerSerializerFormat  format)
2e9f11
+{
2e9f11
+	SoupMessageHeaders *response_headers;
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        response_headers = soup_server_message_get_response_headers (request->message);
2e9f11
+#else
2e9f11
+        response_headers = request->message->response_headers;
2e9f11
+#endif
2e9f11
+        soup_message_headers_set_content_type (response_headers, mimetypes[format], NULL);
2e9f11
+}
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+static void
2e9f11
+server_callback (SoupServer        *server,
2e9f11
+	         SoupServerMessage *message,
2e9f11
+                 const char        *path,
2e9f11
+	         GHashTable        *query,
2e9f11
+                 gpointer           user_data)
2e9f11
+#else
2e9f11
+static void
2e9f11
+server_callback (SoupServer        *server,
2e9f11
+                 SoupMessage       *message,
2e9f11
+                 const char        *path,
2e9f11
+                 GHashTable        *query,
2e9f11
+                 SoupClientContext *client,
2e9f11
+                 gpointer           user_data)
2e9f11
+#endif
2e9f11
+{
2e9f11
+	TrackerHttpServer *http_server = user_data;
2e9f11
+	GSocketAddress *remote_address;
2e9f11
+	TrackerHttpRequest *request;
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        remote_address = soup_server_message_get_remote_address (message);
2e9f11
+#else
2e9f11
+	remote_address = soup_client_context_get_remote_address (client);
2e9f11
+#endif
2e9f11
+
2e9f11
+	request = g_new0 (TrackerHttpRequest, 1);
2e9f11
+	request->server = http_server;
2e9f11
+	request->message = message;
2e9f11
+	soup_server_pause_message (server, message);
2e9f11
+
2e9f11
+	g_signal_emit_by_name (http_server, "request",
2e9f11
+	                       remote_address,
2e9f11
+	                       path,
2e9f11
+	                       query,
2e9f11
+	                       get_supported_formats (request),
2e9f11
+	                       request);
2e9f11
+}
2e9f11
+
2e9f11
+static gboolean
2e9f11
+tracker_http_server_initable_init (GInitable     *initable,
2e9f11
+                                   GCancellable  *cancellable,
2e9f11
+                                   GError       **error)
2e9f11
+{
2e9f11
+	TrackerHttpServerSoup *server = TRACKER_HTTP_SERVER_SOUP (initable);
2e9f11
+	GTlsCertificate *certificate;
2e9f11
+	guint port;
2e9f11
+
2e9f11
+	g_object_get (initable,
2e9f11
+	              "http-certificate", &certificate,
2e9f11
+	              "http-port", &port,
2e9f11
+	              NULL);
2e9f11
+
2e9f11
+	server->server =
2e9f11
+		soup_server_new ("tls-certificate", certificate,
2e9f11
+		                 "server-header", USER_AGENT,
2e9f11
+		                 NULL);
2e9f11
+	soup_server_add_handler (server->server,
2e9f11
+	                         "/sparql",
2e9f11
+	                         server_callback,
2e9f11
+	                         initable,
2e9f11
+	                         NULL);
2e9f11
+	g_clear_object (&certificate);
2e9f11
+
2e9f11
+	return soup_server_listen_all (server->server,
2e9f11
+	                               port,
2e9f11
+	                               0, error);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_soup_initable_iface_init (GInitableIface *iface)
2e9f11
+{
2e9f11
+	iface->init = tracker_http_server_initable_init;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_soup_error (TrackerHttpServer       *server,
2e9f11
+                                TrackerHttpRequest      *request,
2e9f11
+                                gint                     code,
2e9f11
+                                const gchar             *message)
2e9f11
+{
2e9f11
+	TrackerHttpServerSoup *server_soup =
2e9f11
+		TRACKER_HTTP_SERVER_SOUP (server);
2e9f11
+
2e9f11
+	g_assert (request->server == server);
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+	soup_server_message_set_status (request->message, code, message);
2e9f11
+#else
2e9f11
+	soup_message_set_status_full (request->message, code, message);
2e9f11
+#endif
2e9f11
+	soup_server_unpause_message (server_soup->server, request->message);
2e9f11
+	g_free (request);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+handle_write_in_thread (GTask        *task,
2e9f11
+                        gpointer      source_object,
2e9f11
+                        gpointer      task_data,
2e9f11
+                        GCancellable *cancellable)
2e9f11
+{
2e9f11
+	TrackerHttpRequest *request = task_data;
2e9f11
+	gchar buffer[1000];
2e9f11
+	SoupMessageBody *message_body;
2e9f11
+	GError *error = NULL;
2e9f11
+	gssize count;
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+        message_body = soup_server_message_get_response_body (request->message);
2e9f11
+#else
2e9f11
+        message_body = request->message->response_body;
2e9f11
+#endif
2e9f11
+
2e9f11
+	for (;;) {
2e9f11
+		count = g_input_stream_read (request->istream,
2e9f11
+		                             buffer, sizeof (buffer),
2e9f11
+		                             cancellable, &error);
2e9f11
+		if (count < 0) {
2e9f11
+			g_task_return_error (task, error);
2e9f11
+			g_object_unref (task);
2e9f11
+			break;
2e9f11
+		}
2e9f11
+
2e9f11
+		soup_message_body_append (message_body,
2e9f11
+		                          SOUP_MEMORY_COPY,
2e9f11
+		                          buffer, count);
2e9f11
+
2e9f11
+		if ((gsize) count < sizeof (buffer)) {
2e9f11
+			break;
2e9f11
+		}
2e9f11
+	}
2e9f11
+
2e9f11
+	g_input_stream_close (request->istream, cancellable, NULL);
2e9f11
+	soup_message_body_complete (message_body);
2e9f11
+	g_task_return_boolean (task, TRUE);
2e9f11
+	g_object_unref (task);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+write_finished_cb (GObject      *object,
2e9f11
+                   GAsyncResult *result,
2e9f11
+                   gpointer      user_data)
2e9f11
+{
2e9f11
+	TrackerHttpRequest *request = user_data;
2e9f11
+	TrackerHttpServerSoup *server =
2e9f11
+		TRACKER_HTTP_SERVER_SOUP (request->server);
2e9f11
+	GError *error = NULL;
2e9f11
+
2e9f11
+	if (!g_task_propagate_boolean (G_TASK (result), &error)) {
2e9f11
+		tracker_http_server_soup_error (request->server,
2e9f11
+		                                request,
2e9f11
+		                                500,
2e9f11
+		                                error->message);
2e9f11
+		g_clear_error (&error);
2e9f11
+	} else {
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+                soup_server_message_set_status (request->message, 200, NULL);
2e9f11
+#else
2e9f11
+		soup_message_set_status (request->message, 200);
2e9f11
+#endif
2e9f11
+		soup_server_unpause_message (server->server, request->message);
2e9f11
+		g_free (request);
2e9f11
+	}
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_soup_response (TrackerHttpServer       *server,
2e9f11
+                                   TrackerHttpRequest      *request,
2e9f11
+                                   TrackerSerializerFormat  format,
2e9f11
+                                   GInputStream            *content)
2e9f11
+{
2e9f11
+	TrackerHttpServerSoup *server_soup =
2e9f11
+		TRACKER_HTTP_SERVER_SOUP (server);
2e9f11
+
2e9f11
+	g_assert (request->server == server);
2e9f11
+
2e9f11
+	set_message_format (request, format);
2e9f11
+
2e9f11
+	request->istream = content;
2e9f11
+	request->task = g_task_new (server, server_soup->cancellable,
2e9f11
+	                            write_finished_cb, request);
2e9f11
+
2e9f11
+	g_task_set_task_data (request->task, request, NULL);
2e9f11
+	g_task_run_in_thread (request->task, handle_write_in_thread);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_soup_finalize (GObject *object)
2e9f11
+{
2e9f11
+	TrackerHttpServerSoup *server =
2e9f11
+		TRACKER_HTTP_SERVER_SOUP (object);
2e9f11
+
2e9f11
+	g_cancellable_cancel (server->cancellable);
2e9f11
+	g_object_unref (server->cancellable);
2e9f11
+
2e9f11
+	g_clear_object (&server->server);
2e9f11
+
2e9f11
+	G_OBJECT_CLASS (tracker_http_server_soup_parent_class)->finalize (object);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_soup_class_init (TrackerHttpServerSoupClass *klass)
2e9f11
+{
2e9f11
+	TrackerHttpServerClass *server_class = TRACKER_HTTP_SERVER_CLASS (klass);
2e9f11
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
2e9f11
+
2e9f11
+	object_class->finalize = tracker_http_server_soup_finalize;
2e9f11
+
2e9f11
+	server_class->response = tracker_http_server_soup_response;
2e9f11
+	server_class->error = tracker_http_server_soup_error;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_server_soup_init (TrackerHttpServerSoup *server)
2e9f11
+{
2e9f11
+	server->cancellable = g_cancellable_new ();
2e9f11
+}
2e9f11
+
2e9f11
+/* Client */
2e9f11
+struct _TrackerHttpClientSoup
2e9f11
+{
2e9f11
+	TrackerHttpClient parent_instance;
2e9f11
+	SoupSession *session;
2e9f11
+};
2e9f11
+
2e9f11
+G_DEFINE_TYPE (TrackerHttpClientSoup, tracker_http_client_soup,
2e9f11
+               TRACKER_TYPE_HTTP_CLIENT)
2e9f11
+
2e9f11
+static gboolean
2e9f11
+get_content_type_format (SoupMessage              *message,
2e9f11
+                         TrackerSerializerFormat  *format,
2e9f11
+                         GError                  **error)
2e9f11
+{
2e9f11
+	SoupMessageHeaders *response_headers;
2e9f11
+	gint status_code;
2e9f11
+	const gchar *content_type;
2e9f11
+	TrackerSerializerFormat i;
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+	status_code = soup_message_get_status (message);
2e9f11
+	response_headers = soup_message_get_response_headers (message);
2e9f11
+#else
2e9f11
+	status_code = message->status_code;
2e9f11
+	response_headers = message->response_headers;
2e9f11
+#endif
2e9f11
+
2e9f11
+	if (status_code != SOUP_STATUS_OK) {
2e9f11
+		g_set_error (error,
2e9f11
+		             G_IO_ERROR,
2e9f11
+		             G_IO_ERROR_FAILED,
2e9f11
+		             "Unhandled status code %d",
2e9f11
+		             status_code);
2e9f11
+		return FALSE;
2e9f11
+	}
2e9f11
+
2e9f11
+	content_type = soup_message_headers_get_content_type (response_headers, NULL);
2e9f11
+
2e9f11
+	for (i = 0; i < TRACKER_N_SERIALIZER_FORMATS; i++) {
2e9f11
+		if (g_strcmp0 (content_type, mimetypes[i]) == 0) {
2e9f11
+			*format = i;
2e9f11
+			return TRUE;
2e9f11
+		}
2e9f11
+	}
2e9f11
+
2e9f11
+	g_set_error (error,
2e9f11
+	             G_IO_ERROR,
2e9f11
+	             G_IO_ERROR_FAILED,
2e9f11
+	             "Unhandled content type '%s'",
2e9f11
+	             soup_message_headers_get_content_type (response_headers, NULL));
2e9f11
+	return FALSE;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+send_message_cb (GObject      *source,
2e9f11
+                 GAsyncResult *res,
2e9f11
+                 gpointer      user_data)
2e9f11
+{
2e9f11
+	GTask *task = user_data;
2e9f11
+	GInputStream *stream;
2e9f11
+	GError *error = NULL;
2e9f11
+	SoupMessage *message;
2e9f11
+
2e9f11
+	stream = soup_session_send_finish (SOUP_SESSION (source), res, &error);
2e9f11
+	message = g_task_get_task_data (task);
2e9f11
+
2e9f11
+	if (stream) {
2e9f11
+		TrackerSerializerFormat format;
2e9f11
+
2e9f11
+		if (!get_content_type_format (message, &format, &error)) {
2e9f11
+			g_task_return_error (task, error);
2e9f11
+		} else {
2e9f11
+			g_task_set_task_data (task, GUINT_TO_POINTER (format), NULL);
2e9f11
+			g_task_return_pointer (task, stream, g_object_unref);
2e9f11
+		}
2e9f11
+	} else {
2e9f11
+		g_task_return_error (task, error);
2e9f11
+	}
2e9f11
+
2e9f11
+	g_object_unref (task);
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+add_accepted_formats (SoupMessageHeaders *headers,
2e9f11
+                      guint               formats)
2e9f11
+{
2e9f11
+	TrackerSerializerFormat i;
2e9f11
+
2e9f11
+	for (i = 0; i < TRACKER_N_SERIALIZER_FORMATS; i++) {
2e9f11
+		if ((formats & (1 << i)) == 0)
2e9f11
+			continue;
2e9f11
+
2e9f11
+		soup_message_headers_append (headers, "Accept", mimetypes[i]);
2e9f11
+	}
2e9f11
+}
2e9f11
+
2e9f11
+static SoupMessage *
2e9f11
+create_message (const gchar *uri,
2e9f11
+                const gchar *query,
2e9f11
+                guint        formats)
2e9f11
+{
2e9f11
+	SoupMessage *message;
2e9f11
+	SoupMessageHeaders *headers;
2e9f11
+	gchar *full_uri, *query_escaped;
2e9f11
+
2e9f11
+	query_escaped = g_uri_escape_string (query, NULL, FALSE);
2e9f11
+	full_uri = g_strconcat (uri, "?query=", query_escaped, NULL);
2e9f11
+	g_free (query_escaped);
2e9f11
+
2e9f11
+	message = soup_message_new ("GET", full_uri);
2e9f11
+	g_free (full_uri);
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+	headers = soup_message_get_request_headers (message);
2e9f11
+#else
2e9f11
+	headers = message->request_headers;
2e9f11
+#endif
2e9f11
+
2e9f11
+	soup_message_headers_append (headers, "User-Agent", USER_AGENT);
2e9f11
+	add_accepted_formats (headers, formats);
2e9f11
+
2e9f11
+	return message;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_client_soup_send_message_async (TrackerHttpClient   *client,
2e9f11
+                                             const gchar         *uri,
2e9f11
+                                             const gchar         *query,
2e9f11
+                                             guint                formats,
2e9f11
+                                             GCancellable        *cancellable,
2e9f11
+                                             GAsyncReadyCallback  callback,
2e9f11
+                                             gpointer             user_data)
2e9f11
+{
2e9f11
+	TrackerHttpClientSoup *client_soup = TRACKER_HTTP_CLIENT_SOUP (client);
2e9f11
+	SoupMessage *message;
2e9f11
+	GTask *task;
2e9f11
+
2e9f11
+	task = g_task_new (client, cancellable, callback, user_data);
2e9f11
+
2e9f11
+	message = create_message (uri, query, formats);
2e9f11
+	g_task_set_task_data (task, message, g_object_unref);
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+	soup_session_send_async (client_soup->session,
2e9f11
+	                         message,
2e9f11
+	                         G_PRIORITY_DEFAULT,
2e9f11
+	                         cancellable,
2e9f11
+	                         send_message_cb,
2e9f11
+	                         task);
2e9f11
+#else
2e9f11
+	soup_session_send_async (client_soup->session,
2e9f11
+	                         message,
2e9f11
+	                         cancellable,
2e9f11
+	                         send_message_cb,
2e9f11
+	                         task);
2e9f11
+#endif
2e9f11
+}
2e9f11
+
2e9f11
+static GInputStream *
2e9f11
+tracker_http_client_soup_send_message_finish (TrackerHttpClient        *client,
2e9f11
+                                              GAsyncResult             *res,
2e9f11
+                                              TrackerSerializerFormat  *format,
2e9f11
+                                              GError                  **error)
2e9f11
+{
2e9f11
+	if (format)
2e9f11
+		*format = GPOINTER_TO_UINT (g_task_get_task_data (G_TASK (res)));
2e9f11
+
2e9f11
+	return g_task_propagate_pointer (G_TASK (res), error);
2e9f11
+}
2e9f11
+
2e9f11
+static GInputStream *
2e9f11
+tracker_http_client_soup_send_message (TrackerHttpClient        *client,
2e9f11
+                                       const gchar              *uri,
2e9f11
+                                       const gchar              *query,
2e9f11
+                                       guint                     formats,
2e9f11
+                                       GCancellable             *cancellable,
2e9f11
+                                       TrackerSerializerFormat  *format,
2e9f11
+                                       GError                  **error)
2e9f11
+{
2e9f11
+	TrackerHttpClientSoup *client_soup = TRACKER_HTTP_CLIENT_SOUP (client);
2e9f11
+	SoupMessage *message;
2e9f11
+	GInputStream *stream;
2e9f11
+
2e9f11
+	message = create_message (uri, query, formats);
2e9f11
+
2e9f11
+#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
+	stream = soup_session_send (client_soup->session,
2e9f11
+	                            message,
2e9f11
+	                            cancellable,
2e9f11
+	                            error);
2e9f11
+#else
2e9f11
+	stream = soup_session_send (client_soup->session,
2e9f11
+	                            message,
2e9f11
+	                            cancellable,
2e9f11
+	                            error);
2e9f11
+#endif
2e9f11
+	if (!stream)
2e9f11
+		return NULL;
2e9f11
+
2e9f11
+	if (!get_content_type_format (message, format, error)) {
2e9f11
+		g_clear_object (&stream);
2e9f11
+		return NULL;
2e9f11
+	}
2e9f11
+
2e9f11
+	return stream;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_client_soup_class_init (TrackerHttpClientSoupClass *klass)
2e9f11
+{
2e9f11
+	TrackerHttpClientClass *client_class =
2e9f11
+		TRACKER_HTTP_CLIENT_CLASS (klass);
2e9f11
+
2e9f11
+	client_class->send_message_async = tracker_http_client_soup_send_message_async;
2e9f11
+	client_class->send_message_finish = tracker_http_client_soup_send_message_finish;
2e9f11
+	client_class->send_message = tracker_http_client_soup_send_message;
2e9f11
+}
2e9f11
+
2e9f11
+static void
2e9f11
+tracker_http_client_soup_init (TrackerHttpClientSoup *client)
2e9f11
+{
2e9f11
+	client->session = soup_session_new ();
2e9f11
+}
2e9f11
+
2e9f11
+void
2e9f11
+initialize_types (GType *client,
2e9f11
+                  GType *server)
2e9f11
+{
2e9f11
+	*client = TRACKER_TYPE_HTTP_CLIENT_SOUP;
2e9f11
+	*server = TRACKER_TYPE_HTTP_SERVER_SOUP;
2e9f11
+}
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-http-module.h b/src/libtracker-sparql/remote/tracker-http-module.h
2e9f11
new file mode 100644
2e9f11
index 000000000..c013a6f35
2e9f11
--- /dev/null
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-http-module.h
2e9f11
@@ -0,0 +1,39 @@
2e9f11
+/*
2e9f11
+ * Copyright (C) 2022, Red Hat Inc.
2e9f11
+ *
2e9f11
+ * This library is free software; you can redistribute it and/or
2e9f11
+ * modify it under the terms of the GNU Lesser General Public
2e9f11
+ * License as published by the Free Software Foundation; either
2e9f11
+ * version 2.1 of the License, or (at your option) any later version.
2e9f11
+ *
2e9f11
+ * This library is distributed in the hope that it will be useful,
2e9f11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2e9f11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2e9f11
+ * Lesser General Public License for more details.
2e9f11
+ *
2e9f11
+ * You should have received a copy of the GNU Lesser General Public
2e9f11
+ * License along with this library; if not, write to the
2e9f11
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2e9f11
+ * Boston, MA  02110-1301, USA.
2e9f11
+ *
2e9f11
+ * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
+ */
2e9f11
+
2e9f11
+#ifndef TRACKER_HTTP_MODULE_H
2e9f11
+#define TRACKER_HTTP_MODULE_H
2e9f11
+
2e9f11
+#include "tracker-http.h"
2e9f11
+
2e9f11
+#define TRACKER_TYPE_HTTP_SERVER_SOUP (tracker_http_server_soup_get_type ())
2e9f11
+G_DECLARE_FINAL_TYPE (TrackerHttpServerSoup,
2e9f11
+                      tracker_http_server_soup,
2e9f11
+                      TRACKER, HTTP_SERVER_SOUP,
2e9f11
+                      TrackerHttpServer)
2e9f11
+
2e9f11
+#define TRACKER_TYPE_HTTP_CLIENT_SOUP (tracker_http_client_soup_get_type ())
2e9f11
+G_DECLARE_FINAL_TYPE (TrackerHttpClientSoup,
2e9f11
+                      tracker_http_client_soup,
2e9f11
+                      TRACKER, HTTP_CLIENT_SOUP,
2e9f11
+                      TrackerHttpClient)
2e9f11
+
2e9f11
+#endif /* TRACKER_HTTP_MODULE_H */
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From f1687b4f7ab2be4866424b05debac47bfcc8f9c7 Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Sat, 23 Apr 2022 14:18:26 +0200
2e9f11
Subject: [PATCH 10/11] libtracker-sparql: Port remote TrackerSparqlConnection
2e9f11
 to new http helpers
2e9f11
2e9f11
Remove the direct soup dependency by using TrackerHttpClient, that deals
2e9f11
with soup itself. This also means the remote connection objects can move
2e9f11
to the main library code, instead of being built as standalone modules.
2e9f11
2e9f11
In consequence, the older remote modules are no longer built, and their
2e9f11
loading infrastructure removed.
2e9f11
---
2e9f11
 src/libtracker-sparql/meson.build             |  58 +--------
2e9f11
 src/libtracker-sparql/remote/meson.build      |   5 +
2e9f11
 .../remote/tracker-http-module.c              |   2 -
2e9f11
 .../remote/tracker-remote.vala                |  94 ++++----------
2e9f11
 .../remote/tracker-remote.vapi                |  15 +++
2e9f11
 src/libtracker-sparql/tracker-backend.vala    |   5 +
2e9f11
 src/libtracker-sparql/tracker-remote-module.c | 115 ------------------
2e9f11
 7 files changed, 50 insertions(+), 244 deletions(-)
2e9f11
 delete mode 100644 src/libtracker-sparql/tracker-remote-module.c
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
2e9f11
index 2cc0eebab..74a88e224 100644
2e9f11
--- a/src/libtracker-sparql/meson.build
2e9f11
+++ b/src/libtracker-sparql/meson.build
2e9f11
@@ -24,6 +24,7 @@ libtracker_sparql_c_sources = files(
2e9f11
     'tracker-cursor.c',
2e9f11
     'tracker-endpoint.c',
2e9f11
     'tracker-endpoint-dbus.c',
2e9f11
+    'tracker-endpoint-http.c',
2e9f11
     'tracker-error.c',
2e9f11
     'tracker-namespace-manager.c',
2e9f11
     'tracker-notifier.c',
2e9f11
@@ -92,66 +93,11 @@ install_data(
2e9f11
 subdir('bus')
2e9f11
 subdir('direct')
2e9f11
 
2e9f11
-tracker_remote_dependencies = [json_glib, libxml2]
2e9f11
-
2e9f11
-libtracker_sparql_remote_c_sources = files (
2e9f11
-    'tracker-endpoint-http.c',
2e9f11
-    'remote/tracker-remote-statement.c',
2e9f11
-)
2e9f11
-
2e9f11
-remote_sources = [
2e9f11
-    libtracker_sparql_remote_c_sources,
2e9f11
-    'remote/tracker-remote.vapi',
2e9f11
-    'remote/tracker-json-cursor.vala',
2e9f11
-    'remote/tracker-xml-cursor.vala',
2e9f11
-    'remote/tracker-remote.vala',
2e9f11
-]
2e9f11
-
2e9f11
-if libsoup2.found()
2e9f11
-    libtracker_remote_soup2 = shared_module('tracker-remote-soup2', remote_sources,
2e9f11
-        dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep, libsoup2],
2e9f11
-        c_args: tracker_c_args + [
2e9f11
-            '-include', 'config.h',
2e9f11
-            '-include', 'libtracker-sparql/tracker-private.h',
2e9f11
-        ],
2e9f11
-        vala_args: [
2e9f11
-            '--debug',
2e9f11
-            '--pkg', 'posix',
2e9f11
-            # FIXME: Meson has code to add --target-glib automatically, but it
2e9f11
-            # doesn't seem to work here.
2e9f11
-            '--target-glib', glib_required,
2e9f11
-            '--define=SOUP2',
2e9f11
-        ],
2e9f11
-        install: true,
2e9f11
-        install_dir: tracker_internal_libs_dir,
2e9f11
-    )
2e9f11
-endif
2e9f11
-
2e9f11
-if libsoup3.found()
2e9f11
-    libtracker_remote_soup3 = shared_module('tracker-remote-soup3', remote_sources,
2e9f11
-        dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep, libsoup3],
2e9f11
-        c_args: tracker_c_args + [
2e9f11
-            '-include', 'config.h',
2e9f11
-            '-include', 'libtracker-sparql/tracker-private.h',
2e9f11
-        ],
2e9f11
-        vala_args: [
2e9f11
-            '--debug',
2e9f11
-            '--pkg', 'posix',
2e9f11
-            # FIXME: Meson has code to add --target-glib automatically, but it
2e9f11
-            # doesn't seem to work here.
2e9f11
-            '--target-glib', glib_required,
2e9f11
-        ],
2e9f11
-        install: true,
2e9f11
-        install_dir: tracker_internal_libs_dir,
2e9f11
-    )
2e9f11
-endif
2e9f11
-
2e9f11
 libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
2e9f11
     '../libtracker-common/libtracker-common.vapi',
2e9f11
     '../libtracker-data/libtracker-data.vapi',
2e9f11
     'direct/tracker-direct.vapi',
2e9f11
     'tracker-backend.vala',
2e9f11
-    'tracker-remote-module.c',
2e9f11
     remote_files,
2e9f11
     tracker_gresources,
2e9f11
 
2e9f11
@@ -172,7 +118,7 @@ libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
2e9f11
 
2e9f11
     link_whole: [libtracker_sparql_intermediate],
2e9f11
 
2e9f11
-    dependencies: [tracker_common_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, tracker_sparql_vapi_dep, gmodule, libdl],
2e9f11
+    dependencies: [tracker_common_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, tracker_sparql_vapi_dep, gmodule, libdl, json_glib, libxml2],
2e9f11
 )
2e9f11
 
2e9f11
 tracker_sparql_dep = declare_dependency(
2e9f11
diff --git a/src/libtracker-sparql/remote/meson.build b/src/libtracker-sparql/remote/meson.build
2e9f11
index ca137b85e..3d9e0c653 100644
2e9f11
--- a/src/libtracker-sparql/remote/meson.build
2e9f11
+++ b/src/libtracker-sparql/remote/meson.build
2e9f11
@@ -1,5 +1,10 @@
2e9f11
 remote_files = files(
2e9f11
     'tracker-http.c',
2e9f11
+    'tracker-remote-statement.c',
2e9f11
+    'tracker-remote.vapi',
2e9f11
+    'tracker-json-cursor.vala',
2e9f11
+    'tracker-xml-cursor.vala',
2e9f11
+    'tracker-remote.vala',
2e9f11
 )
2e9f11
 
2e9f11
 module_sources = files('tracker-http-module.c')
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-http-module.c b/src/libtracker-sparql/remote/tracker-http-module.c
2e9f11
index 421005001..4fa240654 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-http-module.c
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-http-module.c
2e9f11
@@ -38,8 +38,6 @@ tracker_http_server_get_type (void)
2e9f11
 static const gchar *mimetypes[] = {
2e9f11
 	"application/sparql-results+json",
2e9f11
 	"application/sparql-results+xml",
2e9f11
-	"text/turtle",
2e9f11
-	"application/trig",
2e9f11
 };
2e9f11
 
2e9f11
 G_STATIC_ASSERT (G_N_ELEMENTS (mimetypes) == TRACKER_N_SERIALIZER_FORMATS);
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vala b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
index f3be3147a..9c659c2ef 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vala
2e9f11
@@ -18,96 +18,48 @@
2e9f11
  *
2e9f11
  * Author: Carlos Garnacho <carlosg@gnome.org>
2e9f11
  */
2e9f11
-[CCode (cname = "PACKAGE_VERSION")]
2e9f11
-extern const string PACKAGE_VERSION;
2e9f11
-
2e9f11
 public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
2e9f11
-
2e9f11
-	internal Soup.Session _session;
2e9f11
+	internal HttpClient _client;
2e9f11
 	internal string _base_uri;
2e9f11
 
2e9f11
-	const string XML_TYPE = "application/sparql-results+xml";
2e9f11
-	const string JSON_TYPE = "application/sparql-results+json";
2e9f11
-	const string USER_AGENT = "Tracker/" + PACKAGE_VERSION + " (https://gitlab.gnome.org/GNOME/tracker/issues/; tracker-list@lists.gnome.org) Tracker/" + PACKAGE_VERSION;
2e9f11
-
2e9f11
 	public Connection (string base_uri) {
2e9f11
 		Object ();
2e9f11
 		_base_uri = base_uri;
2e9f11
-		_session = new Soup.Session ();
2e9f11
-	}
2e9f11
-
2e9f11
-	private Soup.Message create_request (string sparql) {
2e9f11
-		var uri = _base_uri + "?query=" + GLib.Uri.escape_string (sparql, null, false);
2e9f11
-		var message = new Soup.Message ("GET", uri);
2e9f11
-#if SOUP2
2e9f11
-		var headers = message.request_headers;
2e9f11
-#else
2e9f11
-                var headers = message.get_request_headers();
2e9f11
-#endif
2e9f11
-
2e9f11
-		headers.append ("User-Agent", USER_AGENT);
2e9f11
-		headers.append ("Accept", JSON_TYPE);
2e9f11
-		headers.append ("Accept", XML_TYPE);
2e9f11
-
2e9f11
-		return message;
2e9f11
+		_client = new HttpClient();
2e9f11
 	}
2e9f11
 
2e9f11
-	private Sparql.Cursor create_cursor (Soup.Message message, string document) throws GLib.Error, Sparql.Error {
2e9f11
-#if SOUP2
2e9f11
-                var status_code = message.status_code;
2e9f11
-                var headers = message.response_headers;
2e9f11
-#else
2e9f11
-                var status_code = message.get_status();
2e9f11
-                var headers = message.get_response_headers();
2e9f11
-#endif
2e9f11
+	private Sparql.Cursor create_cursor (GLib.InputStream stream, SerializerFormat format) throws GLib.Error, Sparql.Error {
2e9f11
+		var buffer = new uchar[20 * 1024 * 1024];
2e9f11
+		size_t len;
2e9f11
+		stream.read_all (buffer, out len, null);
2e9f11
 
2e9f11
-		if (status_code != Soup.Status.OK) {
2e9f11
-			throw new Sparql.Error.UNSUPPORTED ("Unhandled status code %u, document is: %s",
2e9f11
-			                                    status_code, document);
2e9f11
-		}
2e9f11
-
2e9f11
-		var content_type = headers.get_content_type (null);
2e9f11
-		long length = document.length;
2e9f11
-
2e9f11
-		if (content_type == JSON_TYPE) {
2e9f11
-			return new Tracker.Remote.JsonCursor (document, length);
2e9f11
-		} else if (content_type == XML_TYPE) {
2e9f11
-			return new Tracker.Remote.XmlCursor (document, length);
2e9f11
+		if (format == SerializerFormat.JSON) {
2e9f11
+			return new Tracker.Remote.JsonCursor ((string) buffer, (long) len);
2e9f11
+		} else if (format == SerializerFormat.XML) {
2e9f11
+			return new Tracker.Remote.XmlCursor ((string) buffer, (long) len);
2e9f11
 		} else {
2e9f11
-			throw new Sparql.Error.UNSUPPORTED ("Unknown content type '%s', document is: %s", content_type, document);
2e9f11
+			throw new Sparql.Error.UNSUPPORTED ("Unparseable content type, document is: %s", (string) buffer);
2e9f11
 		}
2e9f11
 	}
2e9f11
 
2e9f11
 	public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError {
2e9f11
-		var message = create_request (sparql);
2e9f11
-
2e9f11
-#if SOUP2
2e9f11
-		_session.send_message (message);
2e9f11
-		var data = (string) message.response_body.flatten ().data;
2e9f11
-#else
2e9f11
-		var body = _session.send_and_read (message);
2e9f11
-		var data = (string) body.get_data();
2e9f11
-#endif
2e9f11
-
2e9f11
-		if (data == null || data == "")
2e9f11
-			throw new Sparql.Error.UNSUPPORTED ("Empty response");
2e9f11
-
2e9f11
-		if (cancellable != null && cancellable.is_cancelled ())
2e9f11
-			throw new IOError.CANCELLED ("Operation was cancelled");
2e9f11
+		uint flags =
2e9f11
+			(1 << SerializerFormat.JSON) |
2e9f11
+			(1 << SerializerFormat.XML);
2e9f11
+		SerializerFormat format;
2e9f11
+		var istream = _client.send_message (_base_uri, sparql, flags, cancellable, out format);
2e9f11
 
2e9f11
-                return create_cursor (message, (string) data);
2e9f11
+		return create_cursor (istream, format);
2e9f11
 	}
2e9f11
 
2e9f11
 	public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError {
2e9f11
-		var message = create_request (sparql);
2e9f11
+		uint flags =
2e9f11
+			(1 << SerializerFormat.JSON) |
2e9f11
+			(1 << SerializerFormat.XML);
2e9f11
+		SerializerFormat format;
2e9f11
+		var istream = yield _client.send_message_async (_base_uri, sparql, flags, cancellable, out format);
2e9f11
 
2e9f11
-#if SOUP2
2e9f11
-		yield _session.send_async (message, cancellable);
2e9f11
-                return create_cursor (message, (string) message.response_body.flatten ().data);
2e9f11
-#else
2e9f11
-                var body = yield _session.send_and_read_async (message, GLib.Priority.DEFAULT, cancellable);
2e9f11
-                return create_cursor (message, (string) body.get_data());
2e9f11
-#endif
2e9f11
+		return create_cursor (istream, format);
2e9f11
 	}
2e9f11
 
2e9f11
 	public override Sparql.Statement? query_statement (string sparql, GLib.Cancellable? cancellable = null) throws Sparql.Error {
2e9f11
diff --git a/src/libtracker-sparql/remote/tracker-remote.vapi b/src/libtracker-sparql/remote/tracker-remote.vapi
2e9f11
index caf018b41..d266470e1 100644
2e9f11
--- a/src/libtracker-sparql/remote/tracker-remote.vapi
2e9f11
+++ b/src/libtracker-sparql/remote/tracker-remote.vapi
2e9f11
@@ -3,4 +3,19 @@ namespace Tracker {
2e9f11
 	class Remote.Statement : Sparql.Statement {
2e9f11
 		public Statement (Sparql.Connection conn, string query) throws Sparql.Error;
2e9f11
 	}
2e9f11
+
2e9f11
+	[CCode (cheader_filename = "libtracker-sparql/remote/tracker-http.h")]
2e9f11
+	class HttpClient : GLib.Object {
2e9f11
+		public HttpClient ();
2e9f11
+		public async GLib.InputStream send_message_async (string uri, string query, uint formats, GLib.Cancellable? cancellable, out SerializerFormat format) throws GLib.Error;
2e9f11
+		public GLib.InputStream send_message (string uri, string query, uint formats, GLib.Cancellable? cancellable, out SerializerFormat format) throws GLib.Error;
2e9f11
+	}
2e9f11
+
2e9f11
+	[CCode (cheader_filename = "libtracker-sparql/tracker-enums-private.h")]
2e9f11
+        enum SerializerFormat {
2e9f11
+	        JSON,
2e9f11
+	        XML,
2e9f11
+	        TTL,
2e9f11
+	        TRIG,
2e9f11
+        }
2e9f11
 }
2e9f11
diff --git a/src/libtracker-sparql/tracker-backend.vala b/src/libtracker-sparql/tracker-backend.vala
2e9f11
index af1102d5a..f2d497f6a 100644
2e9f11
--- a/src/libtracker-sparql/tracker-backend.vala
2e9f11
+++ b/src/libtracker-sparql/tracker-backend.vala
2e9f11
@@ -82,3 +82,8 @@ public static async Tracker.Sparql.Connection tracker_sparql_connection_new_asyn
2e9f11
 	yield conn.init_async (Priority.DEFAULT, cancellable);
2e9f11
 	return conn;
2e9f11
 }
2e9f11
+
2e9f11
+public static Tracker.Sparql.Connection tracker_sparql_connection_remote_new (string uri_base) {
2e9f11
+	Tracker.get_debug_flags ();
2e9f11
+	return new Tracker.Remote.Connection (uri_base);
2e9f11
+}
2e9f11
diff --git a/src/libtracker-sparql/tracker-remote-module.c b/src/libtracker-sparql/tracker-remote-module.c
2e9f11
deleted file mode 100644
2e9f11
index 2ca0fd181..000000000
2e9f11
--- a/src/libtracker-sparql/tracker-remote-module.c
2e9f11
+++ /dev/null
2e9f11
@@ -1,115 +0,0 @@
2e9f11
-/* Yuck */
2e9f11
-
2e9f11
-#include "config.h"
2e9f11
-
2e9f11
-#include <gio/gio.h>
2e9f11
-#include <tracker-sparql.h>
2e9f11
-#include <dlfcn.h>
2e9f11
-
2e9f11
-#define LIBSOUP_2_SONAME "libsoup-2.4.so.1"
2e9f11
-
2e9f11
-static gboolean initialized = FALSE;
2e9f11
-
2e9f11
-GType (* remote_endpoint_get_type) (void) = NULL;
2e9f11
-
2e9f11
-TrackerEndpoint * (* remote_endpoint_new) (TrackerSparqlConnection  *sparql_connection,
2e9f11
-                                           guint                     port,
2e9f11
-                                           GTlsCertificate          *certificate,
2e9f11
-                                           GCancellable             *cancellable,
2e9f11
-                                           GError                  **error) = NULL;
2e9f11
-TrackerSparqlConnection * (* remote_connection_new) (const gchar *url_base) = NULL;
2e9f11
-
2e9f11
-static void
2e9f11
-tracker_init_remote (void)
2e9f11
-{
2e9f11
-	const char *modules[3] = { 0 };
2e9f11
-	gpointer handle = NULL;
2e9f11
-	gint i = 0;
2e9f11
-
2e9f11
-	if (initialized)
2e9f11
-		return;
2e9f11
-
2e9f11
-	g_assert (g_module_supported ());
2e9f11
-
2e9f11
-#ifdef HAVE_RTLD_NOLOAD
2e9f11
-	if ((handle = dlopen (LIBSOUP_2_SONAME, RTLD_NOW | RTLD_NOLOAD))) {
2e9f11
-		/* Force load of soup2 module */
2e9f11
-		modules[0] = "libtracker-remote-soup2.so";
2e9f11
-	} else
2e9f11
-#endif
2e9f11
-	{
2e9f11
-		modules[0] = "libtracker-remote-soup3.so";
2e9f11
-		modules[1] = "libtracker-remote-soup2.so";
2e9f11
-	}
2e9f11
-
2e9f11
-	g_clear_pointer (&handle, dlclose);
2e9f11
-
2e9f11
-	for (i = 0; modules[i]; i++) {
2e9f11
-		GModule *remote_module;
2e9f11
-		gchar *module_path;
2e9f11
-
2e9f11
-		if (g_strcmp0 (g_get_current_dir (), BUILDROOT) == 0) {
2e9f11
-			/* Detect in-build runtime of this code, this may happen
2e9f11
-			 * building introspection information or running tests.
2e9f11
-			 * We want the in-tree modules to be loaded then.
2e9f11
-			 */
2e9f11
-			module_path = g_strdup_printf (BUILD_LIBDIR "/%s", modules[i]);
2e9f11
-		} else {
2e9f11
-			module_path = g_strdup_printf (PRIVATE_LIBDIR "/%s", modules[i]);
2e9f11
-		}
2e9f11
-
2e9f11
-		remote_module = g_module_open (module_path,
2e9f11
-		                               G_MODULE_BIND_LAZY |
2e9f11
-		                               G_MODULE_BIND_LOCAL);
2e9f11
-		g_free (module_path);
2e9f11
-
2e9f11
-		if (!remote_module)
2e9f11
-			continue;
2e9f11
-
2e9f11
-		if (!g_module_symbol (remote_module, "tracker_endpoint_http_get_type", (gpointer *) &remote_endpoint_get_type) ||
2e9f11
-		    !g_module_symbol (remote_module, "tracker_endpoint_http_new", (gpointer *) &remote_endpoint_new) ||
2e9f11
-		    !g_module_symbol (remote_module, "tracker_remote_connection_new", (gpointer *) &remote_connection_new)) {
2e9f11
-			g_clear_pointer (&remote_module, g_module_close);
2e9f11
-			continue;
2e9f11
-		}
2e9f11
-
2e9f11
-		g_module_make_resident (remote_module);
2e9f11
-		g_module_close (remote_module);
2e9f11
-		initialized = TRUE;
2e9f11
-		return;
2e9f11
-	}
2e9f11
-
2e9f11
-	g_assert_not_reached ();
2e9f11
-}
2e9f11
-
2e9f11
-GType
2e9f11
-tracker_endpoint_http_get_type (void)
2e9f11
-{
2e9f11
-	tracker_init_remote ();
2e9f11
-
2e9f11
-	return remote_endpoint_get_type ();
2e9f11
-}
2e9f11
-
2e9f11
-TrackerEndpointHttp *
2e9f11
-tracker_endpoint_http_new (TrackerSparqlConnection  *sparql_connection,
2e9f11
-                           guint                     port,
2e9f11
-                           GTlsCertificate          *certificate,
2e9f11
-                           GCancellable             *cancellable,
2e9f11
-                           GError                  **error)
2e9f11
-{
2e9f11
-	tracker_init_remote ();
2e9f11
-
2e9f11
-	return (TrackerEndpointHttp *) remote_endpoint_new (sparql_connection,
2e9f11
-	                                                    port,
2e9f11
-	                                                    certificate,
2e9f11
-	                                                    cancellable,
2e9f11
-	                                                    error);
2e9f11
-}
2e9f11
-
2e9f11
-TrackerSparqlConnection *
2e9f11
-tracker_sparql_connection_remote_new (const gchar *url_base)
2e9f11
-{
2e9f11
-	tracker_init_remote ();
2e9f11
-
2e9f11
-	return remote_connection_new (url_base);
2e9f11
-}
2e9f11
-- 
2e9f11
2.38.1
2e9f11
2e9f11
2e9f11
From 4d6d43495ce831d9f3b52f2f0142a475edad35fe Mon Sep 17 00:00:00 2001
2e9f11
From: Carlos Garnacho <carlosg@gnome.org>
2e9f11
Date: Sat, 23 Apr 2022 14:01:12 +0200
2e9f11
Subject: [PATCH 11/11] libtracker-sparql: Port TrackerEndpointHttp to new HTTP
2e9f11
 module
2e9f11
2e9f11
Use TrackerHttpServer to implement HTTP endpoints, and remove all
2e9f11
soup specific code. This also means the TrackerEndpointHttp object
2e9f11
and type can move out of the elder soup modules, and into the main
2e9f11
library code. All soup 2/3 handling will stay underneath.
2e9f11
---
2e9f11
 src/libtracker-sparql/tracker-endpoint-http.c | 238 ++++--------------
2e9f11
 1 file changed, 55 insertions(+), 183 deletions(-)
2e9f11
2e9f11
diff --git a/src/libtracker-sparql/tracker-endpoint-http.c b/src/libtracker-sparql/tracker-endpoint-http.c
2e9f11
index 5aa82b03d..2a45f1114 100644
2e9f11
--- a/src/libtracker-sparql/tracker-endpoint-http.c
2e9f11
+++ b/src/libtracker-sparql/tracker-endpoint-http.c
2e9f11
@@ -25,15 +25,13 @@
2e9f11
 #include "tracker-serializer.h"
2e9f11
 #include "tracker-private.h"
2e9f11
 
2e9f11
-#include <libsoup/soup.h>
2e9f11
-
2e9f11
-#define SERVER_HEADER "Tracker " PACKAGE_VERSION " (https://gitlab.gnome.org/GNOME/tracker/issues/)"
2e9f11
+#include "remote/tracker-http.h"
2e9f11
 
2e9f11
 typedef struct _TrackerEndpointHttp TrackerEndpointHttp;
2e9f11
 
2e9f11
 struct _TrackerEndpointHttp {
2e9f11
 	TrackerEndpoint parent_instance;
2e9f11
-	SoupServer *server;
2e9f11
+	TrackerHttpServer *server;
2e9f11
 	GTlsCertificate *certificate;
2e9f11
 	guint port;
2e9f11
 	GCancellable *cancellable;
2e9f11
@@ -41,11 +39,7 @@ struct _TrackerEndpointHttp {
2e9f11
 
2e9f11
 typedef struct {
2e9f11
 	TrackerEndpoint *endpoint;
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-        SoupServerMessage *message;
2e9f11
-#else
2e9f11
-	SoupMessage *message;
2e9f11
-#endif
2e9f11
+	TrackerHttpRequest *request;
2e9f11
 	GInputStream *istream;
2e9f11
 	GTask *task;
2e9f11
 	TrackerSerializerFormat format;
2e9f11
@@ -63,9 +57,6 @@ enum {
2e9f11
 	N_PROPS
2e9f11
 };
2e9f11
 
2e9f11
-#define XML_TYPE "application/sparql-results+xml"
2e9f11
-#define JSON_TYPE "application/sparql-results+json"
2e9f11
-
2e9f11
 static GParamSpec *props[N_PROPS];
2e9f11
 static guint signals[N_SIGNALS];
2e9f11
 
2e9f11
@@ -81,80 +72,6 @@ request_free (Request *request)
2e9f11
 	g_free (request);
2e9f11
 }
2e9f11
 
2e9f11
-static void
2e9f11
-handle_request_in_thread (GTask        *task,
2e9f11
-                          gpointer      source_object,
2e9f11
-                          gpointer      task_data,
2e9f11
-                          GCancellable *cancellable)
2e9f11
-{
2e9f11
-	Request *request = task_data;
2e9f11
-	gchar *buffer[1000];
2e9f11
-	gboolean finished = FALSE;
2e9f11
-	SoupMessageBody *message_body;
2e9f11
-	GError *error = NULL;
2e9f11
-	gssize count;
2e9f11
-
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-        message_body = soup_server_message_get_response_body (request->message);
2e9f11
-#else
2e9f11
-        message_body = request->message->response_body;
2e9f11
-#endif
2e9f11
-
2e9f11
-	while (!finished) {
2e9f11
-		count = g_input_stream_read (request->istream,
2e9f11
-		                             buffer, sizeof (buffer),
2e9f11
-		                             cancellable, &error);
2e9f11
-		if (count == -1) {
2e9f11
-			g_task_return_error (task, error);
2e9f11
-			break;
2e9f11
-		} else if (count < sizeof (buffer)) {
2e9f11
-			finished = TRUE;
2e9f11
-		}
2e9f11
-
2e9f11
-		soup_message_body_append (message_body,
2e9f11
-		                          SOUP_MEMORY_COPY,
2e9f11
-		                          buffer, count);
2e9f11
-	}
2e9f11
-
2e9f11
-	g_input_stream_close (request->istream, cancellable, NULL);
2e9f11
-	soup_message_body_complete (message_body);
2e9f11
-	g_task_return_boolean (task, TRUE);
2e9f11
-}
2e9f11
-
2e9f11
-static void
2e9f11
-request_finished_cb (GObject      *object,
2e9f11
-                     GAsyncResult *result,
2e9f11
-                     gpointer      user_data)
2e9f11
-{
2e9f11
-	Request *request = user_data;
2e9f11
-	TrackerEndpointHttp *endpoint_http;
2e9f11
-	GError *error = NULL;
2e9f11
-
2e9f11
-	endpoint_http = TRACKER_ENDPOINT_HTTP (request->endpoint);
2e9f11
-
2e9f11
-	if (!g_task_propagate_boolean (G_TASK (result), &error)) {
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-                soup_server_message_set_status (request->message, 500,
2e9f11
-                                                error ? error->message :
2e9f11
-                                                "No error message");
2e9f11
-#else
2e9f11
-		soup_message_set_status_full (request->message, 500,
2e9f11
-		                              error ? error->message :
2e9f11
-		                              "No error message");
2e9f11
-#endif
2e9f11
-		g_clear_error (&error);
2e9f11
-	} else {
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-                soup_server_message_set_status (request->message, 200, NULL);
2e9f11
-#else
2e9f11
-		soup_message_set_status (request->message, 200);
2e9f11
-#endif
2e9f11
-	}
2e9f11
-
2e9f11
-	soup_server_unpause_message (endpoint_http->server, request->message);
2e9f11
-	request_free (request);
2e9f11
-}
2e9f11
-
2e9f11
 static void
2e9f11
 query_async_cb (GObject      *object,
2e9f11
                 GAsyncResult *result,
2e9f11
@@ -163,141 +80,98 @@ query_async_cb (GObject      *object,
2e9f11
 	TrackerEndpointHttp *endpoint_http;
2e9f11
 	TrackerSparqlCursor *cursor;
2e9f11
 	Request *request = user_data;
2e9f11
+	GInputStream *stream;
2e9f11
 	GError *error = NULL;
2e9f11
 
2e9f11
 	endpoint_http = TRACKER_ENDPOINT_HTTP (request->endpoint);
2e9f11
 	cursor = tracker_sparql_connection_query_finish (TRACKER_SPARQL_CONNECTION (object),
2e9f11
 	                                                 result, &error);
2e9f11
 	if (error) {
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-                soup_server_message_set_status (request->message, 500, error->message);
2e9f11
-#else
2e9f11
-		soup_message_set_status_full (request->message, 500, error->message);
2e9f11
-#endif
2e9f11
-		soup_server_unpause_message (endpoint_http->server, request->message);
2e9f11
+		tracker_http_server_error (endpoint_http->server,
2e9f11
+		                           request->request,
2e9f11
+		                           500,
2e9f11
+		                           error->message);
2e9f11
 		request_free (request);
2e9f11
+		g_error_free (error);
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
-	request->istream = tracker_serializer_new (cursor, request->format);
2e9f11
-	request->task = g_task_new (endpoint_http, endpoint_http->cancellable,
2e9f11
-	                            request_finished_cb, request);
2e9f11
-	g_task_set_task_data (request->task, request, NULL);
2e9f11
-
2e9f11
-	g_task_run_in_thread (request->task, handle_request_in_thread);
2e9f11
+	stream = tracker_serializer_new (cursor, request->format);
2e9f11
+	/* Consumes the input stream */
2e9f11
+	tracker_http_server_response (endpoint_http->server,
2e9f11
+	                              request->request,
2e9f11
+	                              request->format,
2e9f11
+	                              stream);
2e9f11
+	request_free (request);
2e9f11
 }
2e9f11
 
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
 static gboolean
2e9f11
-pick_format (SoupServerMessage       *message,
2e9f11
+pick_format (guint                    formats,
2e9f11
              TrackerSerializerFormat *format)
2e9f11
-#else
2e9f11
-static gboolean
2e9f11
-pick_format (SoupMessage             *message,
2e9f11
-             TrackerSerializerFormat *format)
2e9f11
-#endif
2e9f11
 {
2e9f11
-	SoupMessageHeaders *request_headers, *response_headers;
2e9f11
-
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-        request_headers = soup_server_message_get_request_headers (message);
2e9f11
-        response_headers = soup_server_message_get_response_headers (message);
2e9f11
-#else
2e9f11
-        request_headers = message->request_headers;
2e9f11
-        response_headers = message->response_headers;
2e9f11
-#endif
2e9f11
-
2e9f11
-	if (soup_message_headers_header_contains (request_headers, "Accept", JSON_TYPE)) {
2e9f11
-		soup_message_headers_set_content_type (response_headers, JSON_TYPE, NULL);
2e9f11
-		*format = TRACKER_SERIALIZER_FORMAT_JSON;
2e9f11
-		return TRUE;
2e9f11
-	} else if (soup_message_headers_header_contains (request_headers, "Accept", XML_TYPE)) {
2e9f11
-		soup_message_headers_set_content_type (response_headers, XML_TYPE, NULL);
2e9f11
-		*format = TRACKER_SERIALIZER_FORMAT_XML;
2e9f11
-		return TRUE;
2e9f11
-	} else {
2e9f11
-		return FALSE;
2e9f11
+	TrackerSerializerFormat i;
2e9f11
+
2e9f11
+	for (i = 0; i < TRACKER_N_SERIALIZER_FORMATS; i++) {
2e9f11
+		if ((formats & (1 << i)) != 0) {
2e9f11
+			*format = i;
2e9f11
+			return TRUE;
2e9f11
+		}
2e9f11
 	}
2e9f11
 
2e9f11
 	return FALSE;
2e9f11
 }
2e9f11
 
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
 static void
2e9f11
-server_callback (SoupServer        *server,
2e9f11
-	         SoupServerMessage *message,
2e9f11
-                 const char        *path,
2e9f11
-	         GHashTable        *query,
2e9f11
-                 gpointer           user_data)
2e9f11
-#else
2e9f11
-static void
2e9f11
-server_callback (SoupServer        *server,
2e9f11
-                 SoupMessage       *message,
2e9f11
-                 const char        *path,
2e9f11
-                 GHashTable        *query,
2e9f11
-                 SoupClientContext *client,
2e9f11
-                 gpointer           user_data)
2e9f11
-#endif
2e9f11
+http_server_request_cb (TrackerHttpServer  *server,
2e9f11
+                        GSocketAddress     *remote_address,
2e9f11
+                        const gchar        *path,
2e9f11
+                        GHashTable         *params,
2e9f11
+                        guint               formats,
2e9f11
+                        TrackerHttpRequest *request,
2e9f11
+                        gpointer            user_data)
2e9f11
 {
2e9f11
 	TrackerEndpoint *endpoint = user_data;
2e9f11
 	TrackerSparqlConnection *conn;
2e9f11
 	TrackerSerializerFormat format;
2e9f11
-	GSocketAddress *remote_address;
2e9f11
 	gboolean block = FALSE;
2e9f11
 	const gchar *sparql;
2e9f11
-	Request *request;
2e9f11
+	Request *data;
2e9f11
 
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-        remote_address = soup_server_message_get_remote_address (message);
2e9f11
-#else
2e9f11
-	remote_address = soup_client_context_get_remote_address (client);
2e9f11
-#endif
2e9f11
 	if (remote_address) {
2e9f11
 		g_signal_emit (endpoint, signals[BLOCK_REMOTE_ADDRESS], 0,
2e9f11
 		               remote_address, &block);
2e9f11
 	}
2e9f11
 
2e9f11
 	if (block) {
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-                soup_server_message_set_status (message, 500, "Remote address disallowed");
2e9f11
-#else
2e9f11
-		soup_message_set_status_full (message, 500, "Remote address disallowed");
2e9f11
-#endif
2e9f11
+		tracker_http_server_error (server, request, 500,
2e9f11
+		                           "Remote address disallowed");
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
-	sparql = g_hash_table_lookup (query, "query");
2e9f11
+	sparql = g_hash_table_lookup (params, "query");
2e9f11
 	if (!sparql) {
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-                soup_server_message_set_status (message, 500, "No query given");
2e9f11
-#else
2e9f11
-		soup_message_set_status_full (message, 500, "No query given");
2e9f11
-#endif
2e9f11
+		tracker_http_server_error (server, request, 500,
2e9f11
+		                           "No query given");
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
-	if (!pick_format (message, &format)) {
2e9f11
-#if SOUP_CHECK_VERSION (2, 99, 2)
2e9f11
-                soup_server_message_set_status (message, 500, "No recognized accepted formats");
2e9f11
-#else
2e9f11
-		soup_message_set_status_full (message, 500, "No recognized accepted formats");
2e9f11
-#endif
2e9f11
+	if (!pick_format (formats, &format)) {
2e9f11
+		tracker_http_server_error (server, request, 500,
2e9f11
+		                           "No recognized accepted formats");
2e9f11
 		return;
2e9f11
 	}
2e9f11
 
2e9f11
-	request = g_new0 (Request, 1);
2e9f11
-	request->endpoint = endpoint;
2e9f11
-	request->message = message;
2e9f11
-	request->format = format;
2e9f11
+	data = g_new0 (Request, 1);
2e9f11
+	data->endpoint = endpoint;
2e9f11
+	data->request = request;
2e9f11
+	data->format = format;
2e9f11
 
2e9f11
 	conn = tracker_endpoint_get_sparql_connection (endpoint);
2e9f11
 	tracker_sparql_connection_query_async (conn,
2e9f11
 	                                       sparql,
2e9f11
 	                                       NULL,
2e9f11
 	                                       query_async_cb,
2e9f11
-	                                       request);
2e9f11
-
2e9f11
-	soup_server_pause_message (server, message);
2e9f11
+	                                       data);
2e9f11
 }
2e9f11
 
2e9f11
 static gboolean
2e9f11
@@ -309,18 +183,16 @@ tracker_endpoint_http_initable_init (GInitable     *initable,
2e9f11
 	TrackerEndpointHttp *endpoint_http = TRACKER_ENDPOINT_HTTP (endpoint);
2e9f11
 
2e9f11
 	endpoint_http->server =
2e9f11
-		soup_server_new ("tls-certificate", endpoint_http->certificate,
2e9f11
-		                 "server-header", SERVER_HEADER,
2e9f11
-		                 NULL);
2e9f11
-	soup_server_add_handler (endpoint_http->server,
2e9f11
-	                         "/sparql",
2e9f11
-	                         server_callback,
2e9f11
-	                         initable,
2e9f11
-	                         NULL);
2e9f11
-
2e9f11
-	return soup_server_listen_all (endpoint_http->server,
2e9f11
-	                               endpoint_http->port,
2e9f11
-	                               0, error);
2e9f11
+		tracker_http_server_new (endpoint_http->port,
2e9f11
+		                         endpoint_http->certificate,
2e9f11
+		                         cancellable,
2e9f11
+		                         error);
2e9f11
+	if (!endpoint_http->server)
2e9f11
+		return FALSE;
2e9f11
+
2e9f11
+	g_signal_connect (endpoint_http->server, "request",
2e9f11
+	                  G_CALLBACK (http_server_request_cb), initable);
2e9f11
+	return TRUE;
2e9f11
 }
2e9f11
 
2e9f11
 static void
2e9f11
-- 
2e9f11
2.38.1
2e9f11