diff options
-rw-r--r-- | lib/url/url.c | 125 | ||||
-rw-r--r-- | lib/url/url.h | 1 | ||||
-rw-r--r-- | test/urls/Makefile.am | 6 | ||||
-rw-r--r-- | test/urls/parse-url.c | 13 |
4 files changed, 125 insertions, 20 deletions
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 <assert.h> +#include <stdbool.h> #include <string.h> #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; } diff --git a/lib/url/url.h b/lib/url/url.h index 3cb7cd8..40c1164 100644 --- a/lib/url/url.h +++ b/lib/url/url.h @@ -59,6 +59,7 @@ struct pb_url { }; struct pb_url *pb_url_parse(void *ctx, const char *url_str); +struct pb_url *pb_url_join(void *ctx, const struct pb_url *url, const char *s); const char *pb_url_scheme_name(enum pb_url_scheme scheme); diff --git a/test/urls/Makefile.am b/test/urls/Makefile.am index d16ffdc..2163018 100644 --- a/test/urls/Makefile.am +++ b/test/urls/Makefile.am @@ -30,7 +30,11 @@ check_PROGRAMS = parse-url check_SCRIPTS = run-url-test TESTS = data/double-slash.test \ - data/http-simple.test + data/http-simple.test \ + data/join-full.test \ + data/join-absolute.test \ + data/join-relative.test + TEST_EXTENSIONS = .test TEST_LOG_COMPILER = $(builddir)/run-url-test diff --git a/test/urls/parse-url.c b/test/urls/parse-url.c index d748cdb..cfa6762 100644 --- a/test/urls/parse-url.c +++ b/test/urls/parse-url.c @@ -10,8 +10,8 @@ int main(int argc, char **argv) struct pb_url *url; FILE *null; - if (argc != 2) { - fprintf(stderr, "Usage: %s <URL>\n", argv[0]); + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: %s <URL> [update]\n", argv[0]); return EXIT_FAILURE; } @@ -23,7 +23,14 @@ int main(int argc, char **argv) if (!url) return EXIT_FAILURE; - printf("%s\n", argv[1]); + if (argc == 2) { + printf("%s\n", argv[1]); + + } else { + printf("%s %s\n", argv[1], argv[2]); + url = pb_url_join(NULL, url, argv[2]); + } + printf("scheme\t%s\n", pb_url_scheme_name(url->scheme)); printf("host\t%s\n", url->host); printf("port\t%s\n", url->port); |