diff options
author | Sam Thursfield <sam@afuera.me.uk> | 2022-09-02 17:18:40 +0000 |
---|---|---|
committer | Sam Thursfield <sam@afuera.me.uk> | 2022-09-02 17:18:40 +0000 |
commit | 7a686ee3a46637af5d6a8c2f82f3adb36a30600f (patch) | |
tree | e88501e9accd4f50ebc38cabee3e3b7e51640377 | |
parent | e20c73e5946622d9b2992742de90d682fbba458e (diff) | |
parent | 33031007c73c8e6c2121a86f2642446cbe5fc511 (diff) | |
download | tracker-7a686ee3a46637af5d6a8c2f82f3adb36a30600f.tar.gz |
Merge branch 'wip/carlosg/resource-iri-escapes' into 'master'
libtracker-sparql: Escape illegal characters in IRIREF from TrackerResource
See merge request GNOME/tracker!536
-rw-r--r-- | src/libtracker-sparql/tracker-resource.c | 54 | ||||
-rw-r--r-- | tests/libtracker-sparql/tracker-resource-test.c | 32 |
2 files changed, 83 insertions, 3 deletions
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c index fa3d1fe2f..fc7ea265a 100644 --- a/src/libtracker-sparql/tracker-resource.c +++ b/src/libtracker-sparql/tracker-resource.c @@ -89,6 +89,47 @@ static void set_property (GObject *object, const GValue *value, GParamSpec *pspec); +static char * +escape_iri (const gchar *str) +{ + GString *iri; + + /* Escapes IRI references according to IRIREF in SPARQL grammar definition, + * further validation on IRI validity may happen deeper down. + */ + + if (!str) + return NULL; + + /* Fast path, check whether there's no characters to escape */ + if (!strpbrk (str, + "<>\"{}|^`" + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f")) { + return g_strdup (str); + } + + iri = g_string_new (NULL); + + while (*str != '\0') { + gunichar unichar; + + unichar = g_utf8_get_char (str); + str = g_utf8_next_char (str); + + if (unichar <= 0x20 || + unichar == '<' || unichar == '>' || + unichar == '"' || unichar == '{' || + unichar == '}' || unichar == '|' || + unichar == '^' || unichar == '`' || + unichar == '\\') + g_string_append_printf (iri, "%%%X", unichar); + else + g_string_append_unichar (iri, unichar); + } + + return g_string_free (iri, FALSE); +} static void tracker_resource_class_init (TrackerResourceClass *klass) @@ -302,6 +343,13 @@ validate_pointer (const void *pointer, return TRUE; } +static void +value_set_uri (GValue *value, + const gchar *uri) +{ + g_value_take_string (value, escape_iri (uri)); +} + #define SET_PROPERTY_FOR_GTYPE(name, ctype, gtype, set_function, validate_function) \ void name (TrackerResource *self, \ const char *property_uri, \ @@ -418,7 +466,7 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_string, const char *, G_TYPE_STRING * produces similar RDF to tracker_resource_set_relation(), although * it requires that the URI is previously known. */ -SET_PROPERTY_FOR_GTYPE (tracker_resource_set_uri, const char *, TRACKER_TYPE_URI, g_value_set_string, validate_pointer) +SET_PROPERTY_FOR_GTYPE (tracker_resource_set_uri, const char *, TRACKER_TYPE_URI, value_set_uri, validate_pointer) /** * tracker_resource_set_datetime: @@ -632,7 +680,7 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_string, const char *, G_TYPE_STRING * produces similar RDF to tracker_resource_add_relation(), although * it requires that the URI is previously known. */ -ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_uri, const char *, TRACKER_TYPE_URI, g_value_set_string, validate_pointer) +ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_uri, const char *, TRACKER_TYPE_URI, value_set_uri, validate_pointer) /** * tracker_resource_add_datetime: @@ -860,7 +908,7 @@ tracker_resource_set_identifier (TrackerResource *self, priv = GET_PRIVATE (self); g_clear_pointer (&priv->identifier, g_free); - priv->identifier = g_strdup (identifier); + priv->identifier = escape_iri (identifier); } /** diff --git a/tests/libtracker-sparql/tracker-resource-test.c b/tests/libtracker-sparql/tracker-resource-test.c index dfd7ab188..aa78ea552 100644 --- a/tests/libtracker-sparql/tracker-resource-test.c +++ b/tests/libtracker-sparql/tracker-resource-test.c @@ -220,6 +220,36 @@ test_resource_serialization (void) g_object_unref (copy); } +static void +test_resource_iri_valid_chars (void) +{ + TrackerResource *resource; + + resource = tracker_resource_new ("http://example.com/resource"); + tracker_resource_set_uri (resource, "rdf:type", "http://example.com/resource"); + g_assert_cmpstr (tracker_resource_get_identifier (resource), ==, "http://example.com/resource"); + g_assert_cmpstr (tracker_resource_get_first_uri (resource, "rdf:type"), ==, "http://example.com/resource"); + g_object_unref (resource); + + resource = tracker_resource_new ("http://example.com/♥️"); + tracker_resource_set_uri (resource, "rdf:type", "http://example.com/♥️"); + g_assert_cmpstr (tracker_resource_get_identifier (resource), ==, "http://example.com/♥️"); + g_assert_cmpstr (tracker_resource_get_first_uri (resource, "rdf:type"), ==, "http://example.com/♥️"); + g_object_unref (resource); + + resource = tracker_resource_new ("http://example.com/{}\\`\"^|"); + tracker_resource_set_uri (resource, "rdf:type", "http://example.com/{}\\`\"^|"); + g_assert_cmpstr (tracker_resource_get_identifier (resource), ==, "http://example.com/%7B%7D%5C%60%22%5E%7C"); + g_assert_cmpstr (tracker_resource_get_first_uri (resource, "rdf:type"), ==, "http://example.com/%7B%7D%5C%60%22%5E%7C"); + g_object_unref (resource); + + resource = tracker_resource_new ("http://example.com/\x1f"); + tracker_resource_set_uri (resource, "rdf:type", "http://example.com/\x1f"); + g_assert_cmpstr (tracker_resource_get_identifier (resource), ==, "http://example.com/%1F"); + g_assert_cmpstr (tracker_resource_get_first_uri (resource, "rdf:type"), ==, "http://example.com/%1F"); + g_object_unref (resource); +} + int main (int argc, char **argv) @@ -240,6 +270,8 @@ main (int argc, test_resource_get_set_pointer_validation); g_test_add_func ("/libtracker-sparql/tracker-resource/serialization", test_resource_serialization); + g_test_add_func ("/libtracker-sparql/tracker-resource/iri-valid-chars", + test_resource_iri_valid_chars); return g_test_run (); } |