From 6276a57e76cf22aac639236d4782b56e2e5b9d5e Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 18 Mar 2013 16:48:19 +0800 Subject: lib/url: Add pb_join_url Add a a function to join a string to a base URL Signed-off-by: Jeremy Kerr --- lib/url/url.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 16 deletions(-) (limited to 'lib/url/url.c') diff --git a/lib/url/url.c b/lib/url/url.c index 4e4b961..ae72b10 100644 --- a/lib/url/url.c +++ b/lib/url/url.c @@ -22,6 +22,7 @@ #define _GNU_SOURCE #include +#include #include #include "log/log.h" @@ -36,6 +37,7 @@ struct pb_scheme_info { enum pb_url_scheme scheme; const char *str; unsigned int str_len; + bool has_host; }; static const struct pb_scheme_info schemes[] = { @@ -43,36 +45,43 @@ static const struct pb_scheme_info schemes[] = { .scheme = pb_url_file, .str = "file", .str_len = sizeof("file") - 1, + .has_host = false, }, { .scheme = pb_url_ftp, .str = "ftp", .str_len = sizeof("ftp") - 1, + .has_host = true, }, { .scheme = pb_url_http, .str = "http", .str_len = sizeof("http") - 1, + .has_host = true, }, { .scheme = pb_url_https, .str = "https", .str_len = sizeof("https") - 1, + .has_host = true, }, { .scheme = pb_url_nfs, .str = "nfs", .str_len = sizeof("nfs") - 1, + .has_host = true, }, { .scheme = pb_url_sftp, .str = "sftp", .str_len = sizeof("sftp") - 1, + .has_host = true, }, { .scheme = pb_url_tftp, .str = "tftp", .str_len = sizeof("tftp") - 1, + .has_host = true, }, }; @@ -82,6 +91,21 @@ static const struct pb_scheme_info *file_scheme = &schemes[0]; * pb_url_find_scheme - Find the pb_scheme_info for a URL string. */ +static const struct pb_scheme_info *pb_url_scheme_info( + enum pb_url_scheme scheme) +{ + unsigned int i; + + for (i = 0; i < sizeof(schemes) / sizeof(schemes[0]); i++) { + const struct pb_scheme_info *info = &schemes[i]; + + if (info->scheme == scheme) + return info; + + } + return NULL; +} + static const struct pb_scheme_info *pb_url_find_scheme(const char *url) { static const int sep_len = sizeof("://") - 1; @@ -110,6 +134,23 @@ static const struct pb_scheme_info *pb_url_find_scheme(const char *url) return file_scheme; } +static void pb_url_parse_path(struct pb_url *url) +{ + const char *p = strrchr(url->path, '/'); + + talloc_free(url->dir); + talloc_free(url->file); + + if (p) { + p++; + url->dir = talloc_strndup(url, url->path, p - url->path); + url->file = talloc_strdup(url, p); + } else { + url->dir = NULL; + url->file = talloc_strdup(url, url->path); + } +} + /** * pb_url_parse - Parse a remote file URL. * @ctx: The talloc context to associate with the returned string. @@ -178,16 +219,7 @@ struct pb_url *pb_url_parse(void *ctx, const char *url_str) url->path = talloc_strdup(url, path); } - p = strrchr(url->path, '/'); - - if (p) { - p++; - url->dir = talloc_strndup(url, url->path, p - url->path); - url->file = talloc_strdup(url, p); - } else { - url->dir = NULL; - url->file = talloc_strdup(url, url->path); - } + pb_url_parse_path(url); pb_log(" scheme %d\n", url->scheme); pb_log(" host '%s'\n", url->host); @@ -203,13 +235,74 @@ fail: return NULL; } -const char *pb_url_scheme_name(enum pb_url_scheme scheme) +static bool is_url(const char *str) { - unsigned int i; + return strstr(str, "://") != NULL; +} - for (i = 0; i < sizeof(schemes) / sizeof(schemes[0]); i++) - if (schemes[i].scheme == scheme) - return schemes[i].str; +static void pb_url_update_full(struct pb_url *url) +{ + const struct pb_scheme_info *scheme = pb_url_scheme_info(url->scheme); - return NULL; + assert(scheme); + + talloc_free(url->full); + + url->full = talloc_asprintf(url, "%s://%s%s", scheme->str, + scheme->has_host ? url->host : "", url->path); +} + +static struct pb_url *pb_url_copy(void *ctx, const struct pb_url *url) +{ + struct pb_url *new_url; + + new_url = talloc(ctx, struct pb_url); + new_url->scheme = url->scheme; + new_url->full = talloc_strdup(url, url->full); + + new_url->host = url->host ? talloc_strdup(url, url->host) : NULL; + new_url->port = url->port ? talloc_strdup(url, url->port) : NULL; + new_url->path = url->path ? talloc_strdup(url, url->path) : NULL; + new_url->dir = url->dir ? talloc_strdup(url, url->dir) : NULL; + new_url->file = url->file ? talloc_strdup(url, url->file) : NULL; + + return new_url; +} + +struct pb_url *pb_url_join(void *ctx, const struct pb_url *url, const char *s) +{ + struct pb_url *new_url; + + /* complete url: just parse all info from s */ + if (is_url(s)) + return pb_url_parse(ctx, s); + + new_url = pb_url_copy(ctx, url); + + if (s[0] == '/') { + /* absolute path: replace path of new_url */ + talloc_free(new_url->path); + new_url->path = talloc_strdup(new_url, s); + + } else { + /* relative path: join s to existing path. We know that + * url->dir ends with a slash. */ + char *tmp = new_url->path; + new_url->path = talloc_asprintf(new_url, "%s%s", url->dir, s); + talloc_free(tmp); + } + + /* replace ->dir and ->file with components from ->path */ + pb_url_parse_path(new_url); + + /* and re-generate the full URL */ + pb_url_update_full(new_url); + + return new_url; +} + +const char *pb_url_scheme_name(enum pb_url_scheme scheme) +{ + const struct pb_scheme_info *info = pb_url_scheme_info(scheme); + return info ? info->str : NULL; } -- cgit v1.2.1