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