[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