summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2020-12-07 13:44:45 +0100
committerCarlos Garnacho <carlosg@gnome.org>2020-12-13 20:51:54 +0100
commit8be9514eb886fd3ed55ed74dc86b5c147cbb6425 (patch)
treed1c6927d0323b413dd0e095545727837973db0d8
parent9b884eef2d5544caeb417f5ba1a440e082025791 (diff)
downloadtracker-8be9514eb886fd3ed55ed74dc86b5c147cbb6425.tar.gz
libtracker-sparql: Add HTTP endpoint implementation
Implement partially the server-side bits of https://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/, or at least those bits that we handle in our remote connection side. Most notably, we only handle select queries ATM, this means no modifications, no authentication concerns, etc. This implements the necessary bits to have TrackerEndpoint and tracker_sparql_connection_remote_new() understand each other.
-rw-r--r--docs/reference/libtracker-sparql/libtracker-sparql-sections.txt12
-rw-r--r--docs/reference/libtracker-sparql/libtracker-sparql.types1
-rw-r--r--src/libtracker-sparql/meson.build4
-rw-r--r--src/libtracker-sparql/tracker-endpoint-http.c380
-rw-r--r--src/libtracker-sparql/tracker-endpoint-http.h57
-rw-r--r--src/libtracker-sparql/tracker-endpoint.c15
-rw-r--r--src/libtracker-sparql/tracker-private.h6
-rw-r--r--src/libtracker-sparql/tracker-sparql.h1
8 files changed, 467 insertions, 9 deletions
diff --git a/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt b/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
index 93d73f2b4..1b4f7d845 100644
--- a/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
+++ b/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
@@ -252,9 +252,11 @@ TrackerNotifierClass
<FILE>tracker-endpoint</FILE>
<TITLE>TrackerEndpoint</TITLE>
TrackerEndpoint
+tracker_endpoint_get_sparql_connection
TrackerEndpointDBus
tracker_endpoint_dbus_new
-tracker_endpoint_get_sparql_connection
+TrackerEndpointHttp
+tracker_endpoint_http_new
<SUBSECTION Standard>
TRACKER_TYPE_ENDPOINT
TRACKER_TYPE_ENDPOINT_DBUS
@@ -263,9 +265,17 @@ TRACKER_ENDPOINT_DBUS_CLASS
TRACKER_ENDPOINT_DBUS_GET_CLASS
TRACKER_IS_ENDPOINT_DBUS
TRACKER_IS_ENDPOINT_DBUS_CLASS
+TRACKER_TYPE_ENDPOINT_HTTP
+TRACKER_ENDPOINT_HTTP
+TRACKER_ENDPOINT_HTTP_CLASS
+TRACKER_ENDPOINT_HTTP_GET_CLASS
+TRACKER_IS_ENDPOINT_HTTP
+TRACKER_IS_ENDPOINT_HTTP_CLASS
TrackerEndpointClass
TrackerEndpointDBusClass
+TrackerEndpointHttpClass
tracker_endpoint_dbus_get_type
+tracker_endpoint_http_get_type
</SECTION>
<SECTION>
diff --git a/docs/reference/libtracker-sparql/libtracker-sparql.types b/docs/reference/libtracker-sparql/libtracker-sparql.types
index 4a94c21cc..6b77ba0e7 100644
--- a/docs/reference/libtracker-sparql/libtracker-sparql.types
+++ b/docs/reference/libtracker-sparql/libtracker-sparql.types
@@ -2,6 +2,7 @@
tracker_endpoint_get_type
tracker_endpoint_dbus_get_type
+tracker_endpoint_http_get_type
tracker_namespace_manager_get_type
tracker_notifier_get_type
tracker_notifier_event_get_type
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
index 0e6064e67..570f4b83b 100644
--- a/src/libtracker-sparql/meson.build
+++ b/src/libtracker-sparql/meson.build
@@ -20,6 +20,7 @@ libtracker_sparql_c_sources = files(
'tracker-cursor.c',
'tracker-endpoint.c',
'tracker-endpoint-dbus.c',
+ 'tracker-endpoint-http.c',
'tracker-error.c',
'tracker-namespace-manager.c',
'tracker-notifier.c',
@@ -39,6 +40,7 @@ libtracker_sparql_c_public_headers = files(
'tracker-cursor.h',
'tracker-endpoint.h',
'tracker-endpoint-dbus.h',
+ 'tracker-endpoint-http.h',
'tracker-error.h',
'tracker-namespace-manager.h',
'tracker-notifier.h',
@@ -52,7 +54,7 @@ libtracker_sparql_c_public_headers = files(
libtracker_sparql_intermediate = static_library('tracker-sparql-intermediate',
enum_types,
libtracker_sparql_c_sources,
- dependencies: [tracker_common_dep, json_glib, libxml2],
+ dependencies: [tracker_common_dep, json_glib, libxml2, libsoup],
gnu_symbol_visibility: 'hidden',
)
diff --git a/src/libtracker-sparql/tracker-endpoint-http.c b/src/libtracker-sparql/tracker-endpoint-http.c
new file mode 100644
index 000000000..c2b643c3a
--- /dev/null
+++ b/src/libtracker-sparql/tracker-endpoint-http.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "config.h"
+
+#include "tracker-endpoint-http.h"
+#include "tracker-serializer.h"
+#include "tracker-private.h"
+
+#include <libsoup/soup.h>
+
+#define SERVER_HEADER "Tracker " PACKAGE_VERSION " (https://gitlab.gnome.org/GNOME/tracker/issues/)"
+
+typedef struct _TrackerEndpointHttp TrackerEndpointHttp;
+
+struct _TrackerEndpointHttp {
+ TrackerEndpoint parent_instance;
+ SoupServer *server;
+ GTlsCertificate *certificate;
+ guint port;
+ GCancellable *cancellable;
+};
+
+typedef struct {
+ TrackerEndpoint *endpoint;
+ SoupMessage *message;
+ GInputStream *istream;
+ GTask *task;
+ TrackerSerializerFormat format;
+} Request;
+
+enum {
+ PROP_0,
+ PROP_HTTP_PORT,
+ PROP_HTTP_CERTIFICATE,
+ N_PROPS
+};
+
+#define XML_TYPE "application/sparql-results+xml"
+#define JSON_TYPE "application/sparql-results+json"
+
+static GParamSpec *props[N_PROPS];
+
+static void tracker_endpoint_http_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (TrackerEndpointHttp, tracker_endpoint_http, TRACKER_TYPE_ENDPOINT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, tracker_endpoint_http_initable_iface_init))
+
+static void
+request_free (Request *request)
+{
+ g_clear_object (&request->istream);
+ g_free (request);
+}
+
+static void
+handle_request_in_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ Request *request = task_data;
+ gchar *buffer[1000];
+ gboolean finished = FALSE;
+ SoupMessageBody *message_body;
+ GError *error = NULL;
+ gssize count;
+
+ g_object_get (request->message,
+ "response-body", &message_body,
+ NULL);
+
+ while (!finished) {
+ count = g_input_stream_read (request->istream,
+ buffer, sizeof (buffer),
+ cancellable, &error);
+ if (count == -1) {
+ g_task_return_error (task, error);
+ break;
+ } else if (count < sizeof (buffer)) {
+ finished = TRUE;
+ }
+
+ soup_message_body_append (message_body,
+ SOUP_MEMORY_COPY,
+ buffer, count);
+ }
+
+ g_input_stream_close (request->istream, cancellable, NULL);
+ soup_message_body_complete (message_body);
+ g_task_return_boolean (task, TRUE);
+}
+
+static void
+request_finished_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Request *request = user_data;
+ TrackerEndpointHttp *endpoint_http;
+ GError *error = NULL;
+
+ endpoint_http = TRACKER_ENDPOINT_HTTP (request->endpoint);
+
+ if (!g_task_propagate_boolean (G_TASK (result), &error)) {
+ soup_message_set_status_full (request->message, 500,
+ error ? error->message :
+ "No error message");
+ g_clear_error (&error);
+ } else {
+ soup_message_set_status (request->message, 200);
+ }
+
+ soup_server_unpause_message (endpoint_http->server, request->message);
+ request_free (request);
+}
+
+static void
+query_async_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TrackerEndpointHttp *endpoint_http;
+ TrackerSparqlCursor *cursor;
+ Request *request = user_data;
+ GError *error = NULL;
+
+ endpoint_http = TRACKER_ENDPOINT_HTTP (request->endpoint);
+ cursor = tracker_sparql_connection_query_finish (TRACKER_SPARQL_CONNECTION (object),
+ result, &error);
+ if (error) {
+ soup_message_set_status_full (request->message, 500, error->message);
+ soup_server_unpause_message (endpoint_http->server, request->message);
+ request_free (request);
+ return;
+ }
+
+ request->istream = tracker_serializer_new (cursor, request->format);
+ request->task = g_task_new (endpoint_http, endpoint_http->cancellable,
+ request_finished_cb, request);
+ g_task_set_task_data (request->task, request, NULL);
+
+ g_task_run_in_thread (request->task, handle_request_in_thread);
+}
+
+static gboolean
+pick_format (SoupMessage *message,
+ TrackerSerializerFormat *format)
+{
+ SoupMessageHeaders *request_headers, *response_headers;
+
+ g_object_get (message,
+ "request-headers", &request_headers,
+ "response-headers", &response_headers,
+ NULL);
+
+ if (soup_message_headers_header_contains (request_headers, "Accept", JSON_TYPE)) {
+ soup_message_headers_set_content_type (response_headers, JSON_TYPE, NULL);
+ *format = TRACKER_SERIALIZER_FORMAT_JSON;
+ return TRUE;
+ } else if (soup_message_headers_header_contains (request_headers, "Accept", XML_TYPE)) {
+ soup_message_headers_set_content_type (response_headers, XML_TYPE, NULL);
+ *format = TRACKER_SERIALIZER_FORMAT_XML;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+static void
+server_callback (SoupServer *server,
+ SoupMessage *message,
+ const char *path,
+ GHashTable *query,
+ SoupClientContext *client,
+ gpointer user_data)
+{
+ TrackerEndpoint *endpoint = user_data;
+ TrackerSparqlConnection *conn;
+ TrackerSerializerFormat format;
+ const gchar *sparql;
+ Request *request;
+
+ sparql = g_hash_table_lookup (query, "query");
+ if (!sparql) {
+ soup_message_set_status_full (message, 500, "No query given");
+ return;
+ }
+
+ if (!pick_format (message, &format)) {
+ soup_message_set_status_full (message, 500, "No recognized accepted formats");
+ return;
+ }
+
+ request = g_new0 (Request, 1);
+ request->endpoint = endpoint;
+ request->message = message;
+ request->format = format;
+
+ conn = tracker_endpoint_get_sparql_connection (endpoint);
+ tracker_sparql_connection_query_async (conn,
+ sparql,
+ NULL,
+ query_async_cb,
+ request);
+
+ soup_server_pause_message (server, message);
+}
+
+static gboolean
+tracker_endpoint_http_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerEndpoint *endpoint = TRACKER_ENDPOINT (initable);
+ TrackerEndpointHttp *endpoint_http = TRACKER_ENDPOINT_HTTP (endpoint);
+
+ endpoint_http->server =
+ soup_server_new ("tls-certificate", endpoint_http->certificate,
+ "server-header", SERVER_HEADER,
+ NULL);
+ soup_server_add_handler (endpoint_http->server,
+ "/sparql",
+ server_callback,
+ initable,
+ NULL);
+
+ return soup_server_listen_all (endpoint_http->server,
+ endpoint_http->port,
+ 0, error);
+}
+
+static void
+tracker_endpoint_http_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = tracker_endpoint_http_initable_init;
+}
+
+static void
+tracker_endpoint_http_finalize (GObject *object)
+{
+ TrackerEndpointHttp *endpoint_http = TRACKER_ENDPOINT_HTTP (object);
+
+ g_cancellable_cancel (endpoint_http->cancellable);
+
+ g_clear_object (&endpoint_http->cancellable);
+
+ g_clear_object (&endpoint_http->server);
+
+ G_OBJECT_CLASS (tracker_endpoint_http_parent_class)->finalize (object);
+}
+
+static void
+tracker_endpoint_http_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TrackerEndpointHttp *endpoint_http = TRACKER_ENDPOINT_HTTP (object);
+
+ switch (prop_id) {
+ case PROP_HTTP_PORT:
+ endpoint_http->port = g_value_get_uint (value);
+ break;
+ case PROP_HTTP_CERTIFICATE:
+ endpoint_http->certificate = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tracker_endpoint_http_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TrackerEndpointHttp *endpoint_http = TRACKER_ENDPOINT_HTTP (object);
+
+ switch (prop_id) {
+ case PROP_HTTP_PORT:
+ g_value_set_uint (value, endpoint_http->port);
+ break;
+ case PROP_HTTP_CERTIFICATE:
+ g_value_set_object (value, endpoint_http->certificate);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tracker_endpoint_http_class_init (TrackerEndpointHttpClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = tracker_endpoint_http_finalize;
+ object_class->set_property = tracker_endpoint_http_set_property;
+ object_class->get_property = tracker_endpoint_http_get_property;
+
+ props[PROP_HTTP_PORT] =
+ g_param_spec_uint ("http-port",
+ "HTTP Port",
+ "HTTP Port",
+ 0, G_MAXUINT,
+ 8080,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ props[PROP_HTTP_CERTIFICATE] =
+ g_param_spec_object ("http-certificate",
+ "HTTP certificate",
+ "HTTP certificate",
+ G_TYPE_TLS_CERTIFICATE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, N_PROPS, props);
+}
+
+static void
+tracker_endpoint_http_init (TrackerEndpointHttp *endpoint)
+{
+ endpoint->cancellable = g_cancellable_new ();
+}
+
+/**
+ * tracker_endpoint_http_new:
+ * @sparql_connection: a #TrackerSparqlConnection
+ * @port: HTTP port to listen to
+ * @certificate: (nullable): certificate to use for encription, or %NULL
+ * @cancellable: (nullable): a #GCancellable, or %NULL
+ * @error: pointer to a #GError
+ *
+ * Sets up a Tracker endpoint to listen via HTTP, in the given @port.
+ * If @certificate is not %NULL, HTTPS may be used to connect to the
+ * endpoint.
+ *
+ * Returns: (transfer full): a #TrackerEndpointDBus object.
+ *
+ * Since: 3.1
+ **/
+TrackerEndpointHttp *
+tracker_endpoint_http_new (TrackerSparqlConnection *sparql_connection,
+ guint port,
+ GTlsCertificate *certificate,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (TRACKER_IS_SPARQL_CONNECTION (sparql_connection), NULL);
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (!certificate || G_IS_TLS_CERTIFICATE (certificate), NULL);
+ g_return_val_if_fail (!error || !*error, NULL);
+
+ return g_initable_new (TRACKER_TYPE_ENDPOINT_HTTP, cancellable, error,
+ "http-port", port,
+ "sparql-connection", sparql_connection,
+ "http-certificate", certificate,
+ NULL);
+}
diff --git a/src/libtracker-sparql/tracker-endpoint-http.h b/src/libtracker-sparql/tracker-endpoint-http.h
new file mode 100644
index 000000000..40ef38591
--- /dev/null
+++ b/src/libtracker-sparql/tracker-endpoint-http.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef TRACKER_ENDPOINT_HTTP_H
+#define TRACKER_ENDPOINT_HTTP_H
+
+#if !defined (__LIBTRACKER_SPARQL_INSIDE__) && !defined (TRACKER_COMPILATION)
+#error "only <libtracker-sparql/tracker-sparql.h> must be included directly."
+#endif
+
+#include <libtracker-sparql/tracker-endpoint.h>
+#include <libtracker-sparql/tracker-version.h>
+
+#define TRACKER_TYPE_ENDPOINT_HTTP (tracker_endpoint_http_get_type())
+#define TRACKER_ENDPOINT_HTTP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_ENDPOINT_HTTP, TrackerEndpointHttp))
+#define TRACKER_ENDPOINT_HTTP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_ENDPOINT_HTTP, TrackerEndpointHttpClass))
+#define TRACKER_IS_ENDPOINT_HTTP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_ENDPOINT_HTTP))
+#define TRACKER_IS_ENDPOINT_HTTP_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TRACKER_TYPE_ENDPOINT_HTTP))
+#define TRACKER_ENDPOINT_HTTP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_ENDPOINT_HTTP, TrackerEndpointHttpClass))
+
+/**
+ * TrackerEndpointHttp:
+ *
+ * The <structname>TrackerEndpointHttp</structname> object represents a public
+ * connection to a #TrackerSparqlConnection on a HTTP port.
+ */
+typedef struct _TrackerEndpointHttp TrackerEndpointHttp;
+
+TRACKER_AVAILABLE_IN_3_1
+GType tracker_endpoint_http_get_type (void) G_GNUC_CONST;
+
+TRACKER_AVAILABLE_IN_3_1
+TrackerEndpointHttp * tracker_endpoint_http_new (TrackerSparqlConnection *sparql_connection,
+ guint port,
+ GTlsCertificate *certificate,
+ GCancellable *cancellable,
+ GError **error);
+
+#endif /* TRACKER_ENDPOINT_HTTP_H */
diff --git a/src/libtracker-sparql/tracker-endpoint.c b/src/libtracker-sparql/tracker-endpoint.c
index ddf537af5..6392dbb37 100644
--- a/src/libtracker-sparql/tracker-endpoint.c
+++ b/src/libtracker-sparql/tracker-endpoint.c
@@ -40,20 +40,21 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (TrackerEndpoint, tracker_endpoint, G_TYPE_O
/**
* SECTION: tracker-endpoint
- * @short_description: Expose a database to other processes
+ * @short_description: Expose a database outside the process
* @title: TrackerEndpoint
* @stability: Stable
* @include: tracker-endpoint.h
*
* <para>
- * #TrackerEndpoint allows sharing data with other processes on the system,
- * using a Tracker-specific D-Bus API.
+ * #TrackerEndpoint allows sharing data, either with other processes on the
+ * system via a Tracker-specific D-Bus API, or remote peers via the HTTP
+ * SPARQL protocol.
* </para>
* <para>
- * When it is shared in this way, processes can connect to your database using
- * tracker_sparql_connection_bus_new() and can also fetch data directly from
- * SPARQL queries using the <userinput>SELECT { SERVICE ... }</userinput>
- * syntax.
+ * When it is shared in this way, other peers can connect to your database using
+ * tracker_sparql_connection_bus_new() or tracker_sparql_connection_remote_new(),
+ * and can also fetch data directly from SPARQL queries using the
+ * <userinput>SELECT { SERVICE ... }</userinput> syntax.
* </para>
*/
diff --git a/src/libtracker-sparql/tracker-private.h b/src/libtracker-sparql/tracker-private.h
index 40d9828ca..da93ac862 100644
--- a/src/libtracker-sparql/tracker-private.h
+++ b/src/libtracker-sparql/tracker-private.h
@@ -180,6 +180,12 @@ struct _TrackerEndpointDBusClass {
gchar * (* add_prologue) (TrackerEndpointDBus *endpoint_dbus);
};
+typedef struct _TrackerEndpointHttpClass TrackerEndpointHttpClass;
+
+struct _TrackerEndpointHttpClass {
+ struct _TrackerEndpointClass parent_class;
+};
+
typedef struct _TrackerResourceClass TrackerResourceClass;
struct _TrackerResourceClass
diff --git a/src/libtracker-sparql/tracker-sparql.h b/src/libtracker-sparql/tracker-sparql.h
index cb6309a0d..3b9aa2ffd 100644
--- a/src/libtracker-sparql/tracker-sparql.h
+++ b/src/libtracker-sparql/tracker-sparql.h
@@ -30,6 +30,7 @@
#include <libtracker-sparql/tracker-cursor.h>
#include <libtracker-sparql/tracker-endpoint.h>
#include <libtracker-sparql/tracker-endpoint-dbus.h>
+#include <libtracker-sparql/tracker-endpoint-http.h>
#include <libtracker-sparql/tracker-version.h>
#include <libtracker-sparql/tracker-ontologies.h>
#include <libtracker-sparql/tracker-resource.h>