mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
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.
This commit is contained in:
70
src/net.c
70
src/net.c
@@ -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);
|
||||
|
||||
|
||||
194
tests/network/joinpath.c
Normal file
194
tests/network/joinpath.c
Normal file
@@ -0,0 +1,194 @@
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user