Commit e995f74e by Edward Thomson

net: introduce git_net_url_joinpath

Provide a mechanism to add a path and query string to an existing url
so that we can easily append `/info/refs?...` type url segments to a url
given to us by a user.
parent 471daeea
......@@ -153,6 +153,76 @@ done:
return error;
}
int git_net_url_joinpath(
git_net_url *out,
git_net_url *one,
const char *two)
{
git_buf path = GIT_BUF_INIT;
const char *query;
size_t one_len, two_len;
git_net_url_dispose(out);
if ((query = strchr(two, '?')) != NULL) {
two_len = query - two;
if (*(++query) != '\0') {
out->query = git__strdup(query);
GIT_ERROR_CHECK_ALLOC(out->query);
}
} else {
two_len = strlen(two);
}
/* Strip all trailing `/`s from the first path */
one_len = one->path ? strlen(one->path) : 0;
while (one_len && one->path[one_len - 1] == '/')
one_len--;
/* Strip all leading `/`s from the second path */
while (*two == '/') {
two++;
two_len--;
}
git_buf_put(&path, one->path, one_len);
git_buf_putc(&path, '/');
git_buf_put(&path, two, two_len);
if (git_buf_oom(&path))
return -1;
out->path = git_buf_detach(&path);
if (one->scheme) {
out->scheme = git__strdup(one->scheme);
GIT_ERROR_CHECK_ALLOC(out->scheme);
}
if (one->host) {
out->host = git__strdup(one->host);
GIT_ERROR_CHECK_ALLOC(out->host);
}
if (one->port) {
out->port = git__strdup(one->port);
GIT_ERROR_CHECK_ALLOC(out->port);
}
if (one->username) {
out->username = git__strdup(one->username);
GIT_ERROR_CHECK_ALLOC(out->username);
}
if (one->password) {
out->password = git__strdup(one->password);
GIT_ERROR_CHECK_ALLOC(out->password);
}
return 0;
}
/*
* Some servers strip the query parameters from the Location header
* when sending a redirect. Others leave it in place.
......
......@@ -24,6 +24,12 @@ typedef struct git_net_url {
/** Parses a string containing a URL into a structure. */
extern int git_net_url_parse(git_net_url *url, const char *str);
/** Appends a path and/or query string to the given URL */
extern int git_net_url_joinpath(
git_net_url *out,
git_net_url *in,
const char *path);
/** Ensures that a URL is minimally valid (contains a host, port and path) */
extern bool git_net_url_valid(git_net_url *url);
......
#include "clar_libgit2.h"
#include "net.h"
#include "netops.h"
static git_net_url source, target;
void test_network_joinpath__initialize(void)
{
memset(&source, 0, sizeof(source));
memset(&target, 0, sizeof(target));
}
void test_network_joinpath__cleanup(void)
{
git_net_url_dispose(&source);
git_net_url_dispose(&target);
}
void test_network_joinpath__target_paths_and_queries(void)
{
cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b"));
cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
cl_assert_equal_s(target.path, "/a/b/c/d");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
cl_assert_equal_s(target.path, "/a/b/c/d");
cl_assert_equal_s(target.query, "foo");
git_net_url_dispose(&target);
}
void test_network_joinpath__source_query_removed(void)
{
cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b?query&one&two"));
cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
cl_assert_equal_s(target.path, "/a/b/c/d");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
cl_assert_equal_s(target.path, "/a/b/c/d");
cl_assert_equal_s(target.query, "foo");
git_net_url_dispose(&target);
}
void test_network_joinpath__source_lacks_path(void)
{
cl_git_pass(git_net_url_parse(&source, "http://example.com"));
cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
cl_assert_equal_s(target.path, "/");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, ""));
cl_assert_equal_s(target.path, "/");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
cl_assert_equal_s(target.path, "/foo/bar");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
cl_assert_equal_s(target.path, "/foo/bar");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
}
void test_network_joinpath__source_is_slash(void)
{
cl_git_pass(git_net_url_parse(&source, "http://example.com/"));
cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
cl_assert_equal_s(target.path, "/");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, ""));
cl_assert_equal_s(target.path, "/");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
cl_assert_equal_s(target.path, "/foo/bar");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
cl_assert_equal_s(target.path, "/foo/bar");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
}
void test_network_joinpath__source_has_query(void)
{
cl_git_pass(git_net_url_parse(&source, "http://example.com?query"));
cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
cl_assert_equal_s(target.path, "/");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, ""));
cl_assert_equal_s(target.path, "/");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
cl_assert_equal_s(target.path, "/foo/bar");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
cl_assert_equal_s(target.path, "/asdf");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
cl_assert_equal_s(target.path, "/foo/bar");
cl_assert_equal_s(target.query, "hello");
git_net_url_dispose(&target);
}
void test_network_joinpath__empty_query_ignored(void)
{
cl_git_pass(git_net_url_parse(&source, "http://example.com/foo"));
cl_git_pass(git_net_url_joinpath(&target, &source, "/bar/baz?"));
cl_assert_equal_s(target.path, "/foo/bar/baz");
cl_assert_equal_p(target.query, NULL);
git_net_url_dispose(&target);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment