[vlc-commits] uri: add vlc_uri_resolve()

Rémi Denis-Courmont git at videolan.org
Sun Jul 17 16:13:56 CEST 2016


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Jul 17 16:00:48 2016 +0300| [52f5ce5fb41d75c706bb3017ba90fa1ef0351c6e] | committer: Rémi Denis-Courmont

uri: add vlc_uri_resolve()

This resolves a URI reference relative to a base URI.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=52f5ce5fb41d75c706bb3017ba90fa1ef0351c6e
---

 include/vlc_url.h  |   15 +++++
 src/libvlccore.sym |    1 +
 src/text/url.c     |  165 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 181 insertions(+)

diff --git a/include/vlc_url.h b/include/vlc_url.h
index a013e2c..a827100 100644
--- a/include/vlc_url.h
+++ b/include/vlc_url.h
@@ -115,6 +115,21 @@ VLC_API char *vlc_uri_encode(const char *str) VLC_MALLOC;
 VLC_API char *vlc_uri_compose(const vlc_url_t *) VLC_MALLOC;
 
 /**
+ * Resolves an URI reference.
+ *
+ * Resolves an URI reference relative to a base URI.
+ * If the reference is an absolute URI, then this function simply returns a
+ * copy of the URI reference.
+ *
+ * \param base base URI (as a nul-terminated string)
+ * \param ref URI reference (also as a nul-terminated string)
+ *
+ * \return a heap-allocated nul-terminated string representing the resolved
+ * absolute URI, or NULL if out of memory.
+ */
+VLC_API char *vlc_uri_resolve(const char *base, const char *ref) VLC_MALLOC;
+
+/**
  * Fixes up a URI string.
  *
  * Attempts to convert a nul-terminated string into a syntactically valid URI.
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 5511e51..1e634dd 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -253,6 +253,7 @@ vlc_uri_decode
 vlc_uri_decode_duplicate
 vlc_uri_encode
 vlc_uri_compose
+vlc_uri_resolve
 vlc_uri_fixup
 mdate
 module_config_free
diff --git a/src/text/url.c b/src/text/url.c
index 643bfd3..e3891fe 100644
--- a/src/text/url.c
+++ b/src/text/url.c
@@ -492,6 +492,111 @@ void vlc_UrlClean (vlc_url_t *restrict url)
     free (url->psz_buffer);
 }
 
+/**
+ * Merge paths
+ *
+ * See IETF RFC3986 section 5.2.3 for details.
+ */
+static char *vlc_uri_merge_paths(const char *base, const char *ref)
+{
+    char *str;
+    int len;
+
+    if (base == NULL)
+        len = asprintf(&str, "/%s", ref);
+    else
+    {
+        const char *end = strrchr(base, '/');
+
+        if (end != NULL)
+            end++;
+        else
+            end = base;
+
+        len = asprintf(&str, "%.*s%s", (int)(end - base), base, ref);
+    }
+
+    if (unlikely(len == -1))
+        str = NULL;
+    return str;
+}
+
+/**
+ * Remove dot segments
+ *
+ * See IETF RFC3986 section 5.2.4 for details.
+ */
+static char *vlc_uri_remove_dot_segments(char *str)
+{
+    char *input = str, *output = str;
+
+    while (input[0] != '\0')
+    {
+        assert(output <= input);
+
+        if (strncmp(input, "../", 3) == 0)
+        {
+            input += 3;
+            continue;
+        }
+        if (strncmp(input, "./", 2) == 0)
+        {
+            input += 2;
+            continue;
+        }
+        if (strncmp(input, "/./", 3) == 0)
+        {
+            input += 2;
+            continue;
+        }
+        if (strcmp(input, "/.") == 0)
+        {
+            input[1] = '\0';
+            continue;
+        }
+        if (strncmp(input, "/../", 4) == 0)
+        {
+            input += 3;
+            output = memrchr(str, '/', output - str);
+            if (output == NULL)
+                output = str;
+            continue;
+        }
+        if (strcmp(input, "/..") == 0)
+        {
+            input[1] = '\0';
+            output = memrchr(str, '/', output - str);
+            if (output == NULL)
+                output = str;
+            continue;
+        }
+        if (strcmp(input, ".") == 0)
+        {
+            input++;
+            continue;
+        }
+        if (strcmp(input, "..") == 0)
+        {
+            input += 2;
+            continue;
+        }
+
+        if (input[0] == '/')
+            *(output++) = *(input++);
+
+        size_t len = strcspn(input, "/");
+
+        if (input != output)
+            memmove(output, input, len);
+
+        input += len;
+        output += len;
+    }
+
+    output[0] = '\0';
+    return str;
+}
+
 char *vlc_uri_compose(const vlc_url_t *uri)
 {
     char *buf, *enc;
@@ -553,6 +658,66 @@ error:
     return NULL;
 }
 
+char *vlc_uri_resolve(const char *base, const char *ref)
+{
+    vlc_url_t base_uri, rel_uri;
+    vlc_url_t tgt_uri;
+    char *pathbuf = NULL, *ret = NULL;
+
+    vlc_UrlParse(&rel_uri, ref);
+
+    if (rel_uri.psz_protocol != NULL)
+    {   /* Short circuit in case of absolute URI */
+        vlc_UrlClean(&rel_uri);
+        return strdup(ref);
+    }
+
+    vlc_UrlParse(&base_uri, base);
+
+    /* RFC3986 section 5.2.2 */
+    do
+    {
+        tgt_uri = rel_uri;
+        tgt_uri.psz_protocol = base_uri.psz_protocol;
+
+        if (rel_uri.psz_host != NULL)
+            break;
+
+        tgt_uri.psz_username = base_uri.psz_username;
+        tgt_uri.psz_password = base_uri.psz_password;
+        tgt_uri.psz_host = base_uri.psz_host;
+        tgt_uri.i_port = base_uri.i_port;
+
+        if (rel_uri.psz_path == NULL || rel_uri.psz_path[0] == '\0')
+        {
+            tgt_uri.psz_path = base_uri.psz_path;
+            if (rel_uri.psz_option == NULL)
+                tgt_uri.psz_option = base_uri.psz_option;
+            break;
+        }
+
+        if (rel_uri.psz_path[0] == '/')
+            break;
+
+        pathbuf = vlc_uri_merge_paths(base_uri.psz_path, rel_uri.psz_path);
+        if (unlikely(pathbuf == NULL))
+            goto error;
+
+        tgt_uri.psz_path = pathbuf;
+    }
+    while (0);
+
+    if (tgt_uri.psz_path != NULL)
+        vlc_uri_remove_dot_segments(tgt_uri.psz_path);
+
+    ret = vlc_uri_compose(&tgt_uri);
+error:
+    free(pathbuf);
+    vlc_UrlClean(&base_uri);
+    vlc_UrlClean(&rel_uri);
+    return ret;
+}
+
 char *vlc_uri_fixup(const char *str)
 {
     /* Rule number one is do not change a (potentially) valid URI */



More information about the vlc-commits mailing list