summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/url/url.c125
-rw-r--r--lib/url/url.h1
-rw-r--r--test/urls/Makefile.am6
-rw-r--r--test/urls/parse-url.c13
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);
OpenPOWER on IntegriCloud