aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-07-11 01:24:54 +0200
committerDavid Robillard <d@drobilla.net>2018-07-12 08:30:47 +0200
commit7e10a58373dbbb850c4f4daeb90ce2d9739da441 (patch)
tree34aec3ef2a1754310c252c299a9b14f910625975
parent01ad406bd8defd4c11ebeaf53f45f7ddf4cc7717 (diff)
downloadserd-7e10a58373dbbb850c4f4daeb90ce2d9739da441.tar.gz
serd-7e10a58373dbbb850c4f4daeb90ce2d9739da441.tar.bz2
serd-7e10a58373dbbb850c4f4daeb90ce2d9739da441.zip
Fix making relative URIs that are shorter than, but under, the root
-rw-r--r--src/serd_internal.h44
-rw-r--r--tests/serd_test.c9
2 files changed, 39 insertions, 14 deletions
diff --git a/src/serd_internal.h b/src/serd_internal.h
index 04f9feaa..18cc74bd 100644
--- a/src/serd_internal.h
+++ b/src/serd_internal.h
@@ -431,36 +431,52 @@ uri_path_at(const SerdURI* uri, size_t i)
}
}
-/** Return true iff `uri` shares path components with `root` */
-static inline bool
-uri_is_related(const SerdURI* uri, const SerdURI* root)
+/**
+ Return the index of the first differing character after the last root slash,
+ or zero if `uri` is not under `root`.
+*/
+static inline size_t
+uri_rooted_index(const SerdURI* uri, const SerdURI* root)
{
if (!root || !root->scheme.len ||
!chunk_equals(&root->scheme, &uri->scheme) ||
!chunk_equals(&root->authority, &uri->authority)) {
- return false;
+ return 0;
}
- bool differ = false;
- const size_t path_len = uri_path_len(uri);
- const size_t root_len = uri_path_len(root);
+ bool differ = false;
+ const size_t path_len = uri_path_len(uri);
+ const size_t root_len = uri_path_len(root);
+ size_t last_root_slash = 0;
for (size_t i = 0; i < path_len && i < root_len; ++i) {
- if (uri_path_at(uri, i) != uri_path_at(root, i)) {
- differ = true;
- }
- if (differ && uri_path_at(root, i) == '/') {
- return false;
+ const uint8_t u = uri_path_at(uri, i);
+ const uint8_t r = uri_path_at(root, i);
+
+ differ = differ || u != r;
+ if (r == '/') {
+ last_root_slash = i;
+ if (differ) {
+ return 0;
+ }
}
}
- return true;
+ return last_root_slash + 1;
+}
+
+/** Return true iff `uri` shares path components with `root` */
+static inline bool
+uri_is_related(const SerdURI* uri, const SerdURI* root)
+{
+ return uri_rooted_index(uri, root) > 0;
}
/** Return true iff `uri` is within the base of `root` */
static inline bool
uri_is_under(const SerdURI* uri, const SerdURI* root)
{
- return uri->path.len >= root->path.len && uri_is_related(uri, root);
+ const size_t index = uri_rooted_index(uri, root);
+ return index > 0 && uri->path.len > index;
}
static inline bool
diff --git a/tests/serd_test.c b/tests/serd_test.c
index a987b153..e312ad04 100644
--- a/tests/serd_test.c
+++ b/tests/serd_test.c
@@ -422,6 +422,15 @@ main(void)
FAILF("Bad relative URI %s (expected 'http://example.org/')\n", noup.buf);
}
+ SerdNode x = serd_node_from_string(SERD_URI, USTR("http://example.org/foo/x"));
+ SerdURI x_uri;
+ serd_uri_parse(x.buf, &x_uri);
+
+ SerdNode x_rel = serd_node_new_relative_uri(&x_uri, &abs_uri, &abs_uri, NULL);
+ if (strcmp((const char*)x_rel.buf, "x")) {
+ FAILF("Bad relative URI %s (expected 'x')\n", x_rel.buf);
+ }
+
serd_node_free(&noup);
serd_node_free(&up);
serd_node_free(&rel);