Unverified Commit 002b2ffe by Edward Thomson Committed by GitHub

Merge pull request #6026 from libgit2/ethomson/proxy

Update proxy configuration
parents d56b4079 3c0f14cc
...@@ -35,6 +35,46 @@ static const char *default_port_for_scheme(const char *scheme) ...@@ -35,6 +35,46 @@ static const char *default_port_for_scheme(const char *scheme)
return NULL; return NULL;
} }
int git_net_url_dup(git_net_url *out, git_net_url *in)
{
if (in->scheme) {
out->scheme = git__strdup(in->scheme);
GIT_ERROR_CHECK_ALLOC(out->scheme);
}
if (in->host) {
out->host = git__strdup(in->host);
GIT_ERROR_CHECK_ALLOC(out->host);
}
if (in->port) {
out->port = git__strdup(in->port);
GIT_ERROR_CHECK_ALLOC(out->port);
}
if (in->path) {
out->path = git__strdup(in->path);
GIT_ERROR_CHECK_ALLOC(out->path);
}
if (in->query) {
out->query = git__strdup(in->query);
GIT_ERROR_CHECK_ALLOC(out->query);
}
if (in->username) {
out->username = git__strdup(in->username);
GIT_ERROR_CHECK_ALLOC(out->username);
}
if (in->password) {
out->password = git__strdup(in->password);
GIT_ERROR_CHECK_ALLOC(out->password);
}
return 0;
}
int git_net_url_parse(git_net_url *url, const char *given) int git_net_url_parse(git_net_url *url, const char *given)
{ {
struct http_parser_url u = {0}; struct http_parser_url u = {0};
...@@ -404,6 +444,80 @@ int git_net_url_fmt_path(git_buf *buf, git_net_url *url) ...@@ -404,6 +444,80 @@ int git_net_url_fmt_path(git_buf *buf, git_net_url *url)
return git_buf_oom(buf) ? -1 : 0; return git_buf_oom(buf) ? -1 : 0;
} }
static bool matches_pattern(
git_net_url *url,
const char *pattern,
size_t pattern_len)
{
const char *domain, *port = NULL, *colon;
size_t host_len, domain_len, port_len = 0, wildcard = 0;
GIT_UNUSED(url);
GIT_UNUSED(pattern);
if (!pattern_len)
return false;
else if (pattern_len == 1 && pattern[0] == '*')
return true;
else if (pattern_len > 1 && pattern[0] == '*' && pattern[1] == '.')
wildcard = 2;
else if (pattern[0] == '.')
wildcard = 1;
domain = pattern + wildcard;
domain_len = pattern_len - wildcard;
if ((colon = memchr(domain, ':', domain_len)) != NULL) {
domain_len = colon - domain;
port = colon + 1;
port_len = pattern_len - wildcard - domain_len - 1;
}
/* A pattern's port *must* match if it's specified */
if (port_len && git__strlcmp(url->port, port, port_len) != 0)
return false;
/* No wildcard? Host must match exactly. */
if (!wildcard)
return !git__strlcmp(url->host, domain, domain_len);
/* Wildcard: ensure there's (at least) a suffix match */
if ((host_len = strlen(url->host)) < domain_len ||
memcmp(url->host + (host_len - domain_len), domain, domain_len))
return false;
/* The pattern is *.domain and the host is simply domain */
if (host_len == domain_len)
return true;
/* The pattern is *.domain and the host is foo.domain */
return (url->host[host_len - domain_len - 1] == '.');
}
bool git_net_url_matches_pattern(git_net_url *url, const char *pattern)
{
return matches_pattern(url, pattern, strlen(pattern));
}
bool git_net_url_matches_pattern_list(
git_net_url *url,
const char *pattern_list)
{
const char *pattern, *pattern_end, *sep;
for (pattern = pattern_list;
pattern && *pattern;
pattern = sep ? sep + 1 : NULL) {
sep = strchr(pattern, ',');
pattern_end = sep ? sep : strchr(pattern, '\0');
if (matches_pattern(url, pattern, (pattern_end - pattern)))
return true;
}
return false;
}
void git_net_url_dispose(git_net_url *url) void git_net_url_dispose(git_net_url *url)
{ {
if (url->username) if (url->username)
......
...@@ -21,6 +21,9 @@ typedef struct git_net_url { ...@@ -21,6 +21,9 @@ typedef struct git_net_url {
#define GIT_NET_URL_INIT { NULL } #define GIT_NET_URL_INIT { NULL }
/** Duplicate a URL */
extern int git_net_url_dup(git_net_url *out, git_net_url *in);
/** Parses a string containing a URL into a structure. */ /** Parses a string containing a URL into a structure. */
extern int git_net_url_parse(git_net_url *url, const char *str); extern int git_net_url_parse(git_net_url *url, const char *str);
...@@ -54,6 +57,14 @@ extern int git_net_url_fmt(git_buf *out, git_net_url *url); ...@@ -54,6 +57,14 @@ extern int git_net_url_fmt(git_buf *out, git_net_url *url);
/** Place the path and query string into the given buffer. */ /** Place the path and query string into the given buffer. */
extern int git_net_url_fmt_path(git_buf *buf, git_net_url *url); extern int git_net_url_fmt_path(git_buf *buf, git_net_url *url);
/** Determines if the url matches given pattern or pattern list */
extern bool git_net_url_matches_pattern(
git_net_url *url,
const char *pattern);
extern bool git_net_url_matches_pattern_list(
git_net_url *url,
const char *pattern_list);
/** Disposes the contents of the structure. */ /** Disposes the contents of the structure. */
extern void git_net_url_dispose(git_net_url *url); extern void git_net_url_dispose(git_net_url *url);
......
...@@ -849,75 +849,140 @@ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote ...@@ -849,75 +849,140 @@ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote
return remote->transport->ls(out, size, remote->transport); return remote->transport->ls(out, size, remote->transport);
} }
int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url) static int lookup_config(char **out, git_config *cfg, const char *name)
{ {
git_config *cfg;
git_config_entry *ce = NULL; git_config_entry *ce = NULL;
git_buf val = GIT_BUF_INIT;
int error; int error;
GIT_ASSERT_ARG(remote); if ((error = git_config__lookup_entry(&ce, cfg, name, false)) < 0)
return error;
if (!proxy_url || !remote->repo) if (ce && ce->value) {
return -1; *out = git__strdup(ce->value);
GIT_ERROR_CHECK_ALLOC(*out);
} else {
error = GIT_ENOTFOUND;
}
git_config_entry_free(ce);
return error;
}
*proxy_url = NULL; static void url_config_trim(git_net_url *url)
{
size_t len = strlen(url->path);
if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0) if (url->path[len - 1] == '/') {
return error; len--;
} else {
while (len && url->path[len - 1] != '/')
len--;
}
/* Go through the possible sources for proxy configuration, from most specific url->path[len] = '\0';
* to least specific. */ }
static int http_proxy_config(char **out, git_remote *remote, git_net_url *url)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
git_net_url lookup_url = GIT_NET_URL_INIT;
int error;
if ((error = git_net_url_dup(&lookup_url, url)) < 0 ||
(error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
goto done;
/* remote.<name>.proxy config setting */ /* remote.<name>.proxy config setting */
if (remote->name && remote->name[0]) { if (remote->name && remote->name[0]) {
git_buf buf = GIT_BUF_INIT; git_buf_clear(&buf);
if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0) if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0 ||
return error; (error = lookup_config(out, cfg, buf.ptr)) != GIT_ENOTFOUND)
goto done;
}
error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false); while (true) {
git_buf_dispose(&buf); git_buf_clear(&buf);
if (error < 0) if ((error = git_buf_puts(&buf, "http.")) < 0 ||
return error; (error = git_net_url_fmt(&buf, &lookup_url)) < 0 ||
(error = git_buf_puts(&buf, ".proxy")) < 0 ||
(error = lookup_config(out, cfg, buf.ptr)) != GIT_ENOTFOUND)
goto done;
if (ce && ce->value) { if (! lookup_url.path[0])
*proxy_url = git__strdup(ce->value); break;
goto found;
} url_config_trim(&lookup_url);
} }
/* http.proxy config setting */ git_buf_clear(&buf);
if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
return error;
if (ce && ce->value) { error = lookup_config(out, cfg, "http.proxy");
*proxy_url = git__strdup(ce->value);
goto found; done:
} git_buf_dispose(&buf);
git_net_url_dispose(&lookup_url);
return error;
}
static int http_proxy_env(char **out, git_remote *remote, git_net_url *url)
{
git_buf proxy_env = GIT_BUF_INIT, no_proxy_env = GIT_BUF_INIT;
bool use_ssl = (strcmp(url->scheme, "https") == 0);
int error;
GIT_UNUSED(remote);
/* http_proxy / https_proxy environment variables */ /* http_proxy / https_proxy environment variables */
error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy"); error = git__getenv(&proxy_env, use_ssl ? "https_proxy" : "http_proxy");
/* try uppercase environment variables */ /* try uppercase environment variables */
if (error == GIT_ENOTFOUND) if (error == GIT_ENOTFOUND)
error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY"); error = git__getenv(&proxy_env, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
if (error < 0) { if (error)
if (error == GIT_ENOTFOUND) { goto done;
git_error_clear();
error = 0;
}
return error; /* no_proxy/NO_PROXY environment variables */
} error = git__getenv(&no_proxy_env, "no_proxy");
*proxy_url = git_buf_detach(&val); if (error == GIT_ENOTFOUND)
error = git__getenv(&no_proxy_env, "NO_PROXY");
found: if (error && error != GIT_ENOTFOUND)
GIT_ERROR_CHECK_ALLOC(*proxy_url); goto done;
git_config_entry_free(ce);
if (!git_net_url_matches_pattern_list(url, no_proxy_env.ptr))
*out = git_buf_detach(&proxy_env);
else
error = GIT_ENOTFOUND;
done:
git_buf_dispose(&proxy_env);
git_buf_dispose(&no_proxy_env);
return error;
}
int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url)
{
int error;
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(remote);
GIT_ASSERT_ARG(remote->repo);
*out = NULL;
/*
* Go through the possible sources for proxy configuration,
* Examine the various git config options first, then
* consult environment variables.
*/
if ((error = http_proxy_config(out, remote, url)) != GIT_ENOTFOUND ||
(error = http_proxy_env(out, remote, url)) != GIT_ENOTFOUND)
return error;
return 0; return 0;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "refspec.h" #include "refspec.h"
#include "vector.h" #include "vector.h"
#include "net.h"
#define GIT_REMOTE_ORIGIN "origin" #define GIT_REMOTE_ORIGIN "origin"
...@@ -46,7 +47,7 @@ typedef struct git_remote_connection_opts { ...@@ -46,7 +47,7 @@ typedef struct git_remote_connection_opts {
int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn); int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn);
int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks); int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks);
int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url); int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url);
git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname); git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname);
git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname); git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname);
......
...@@ -290,7 +290,6 @@ static int lookup_proxy( ...@@ -290,7 +290,6 @@ static int lookup_proxy(
{ {
const char *proxy; const char *proxy;
git_remote *remote; git_remote *remote;
bool use_ssl;
char *config = NULL; char *config = NULL;
int error = 0; int error = 0;
...@@ -304,9 +303,8 @@ static int lookup_proxy( ...@@ -304,9 +303,8 @@ static int lookup_proxy(
case GIT_PROXY_AUTO: case GIT_PROXY_AUTO:
remote = transport->owner->owner; remote = transport->owner->owner;
use_ssl = !strcmp(transport->server.url.scheme, "https");
error = git_remote__get_http_proxy(remote, use_ssl, &config); error = git_remote__http_proxy(&config, remote, &transport->server.url);
if (error || !config) if (error || !config)
goto done; goto done;
......
...@@ -429,7 +429,7 @@ static int winhttp_stream_connect(winhttp_stream *s) ...@@ -429,7 +429,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
proxy_opts = &t->owner->proxy; proxy_opts = &t->owner->proxy;
if (proxy_opts->type == GIT_PROXY_AUTO) { if (proxy_opts->type == GIT_PROXY_AUTO) {
/* Set proxy if necessary */ /* Set proxy if necessary */
if (git_remote__get_http_proxy(t->owner->owner, (strcmp(t->server.url.scheme, "https") == 0), &proxy_url) < 0) if (git_remote__http_proxy(&proxy_url, t->owner->owner, &t->server.url) < 0)
goto on_error; goto on_error;
} }
else if (proxy_opts->type == GIT_PROXY_SPECIFIED) { else if (proxy_opts->type == GIT_PROXY_SPECIFIED) {
...@@ -742,7 +742,7 @@ static void CALLBACK winhttp_status( ...@@ -742,7 +742,7 @@ static void CALLBACK winhttp_status(
git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status); git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
break; break;
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
((winhttp_stream *) ctx)->status_sending_request_reached = 1; ((winhttp_stream *) ctx)->status_sending_request_reached = 1;
......
...@@ -168,6 +168,17 @@ extern int git__strncasecmp(const char *a, const char *b, size_t sz); ...@@ -168,6 +168,17 @@ extern int git__strncasecmp(const char *a, const char *b, size_t sz);
extern int git__strcasesort_cmp(const char *a, const char *b); extern int git__strcasesort_cmp(const char *a, const char *b);
/*
* Compare some NUL-terminated `a` to a possibly non-NUL terminated
* `b` of length `b_len`; like `strncmp` but ensuring that
* `strlen(a) == b_len` as well.
*/
GIT_INLINE(int) git__strlcmp(const char *a, const char *b, size_t b_len)
{
int cmp = strncmp(a, b, b_len);
return cmp ? cmp : (int)a[b_len];
}
typedef struct { typedef struct {
git_atomic32 refcount; git_atomic32 refcount;
void *owner; void *owner;
......
...@@ -123,3 +123,14 @@ void test_core_string__strcasecmp(void) ...@@ -123,3 +123,14 @@ void test_core_string__strcasecmp(void)
cl_assert(git__strcasecmp("et", "e\342\202\254ghi=") < 0); cl_assert(git__strcasecmp("et", "e\342\202\254ghi=") < 0);
cl_assert(git__strcasecmp("\303\215", "\303\255") < 0); cl_assert(git__strcasecmp("\303\215", "\303\255") < 0);
} }
void test_core_string__strlcmp(void)
{
const char foo[3] = { 'f', 'o', 'o' };
cl_assert(git__strlcmp("foo", "foo", 3) == 0);
cl_assert(git__strlcmp("foo", foo, 3) == 0);
cl_assert(git__strlcmp("foo", "foobar", 3) == 0);
cl_assert(git__strlcmp("foobar", "foo", 3) > 0);
cl_assert(git__strlcmp("foo", "foobar", 6) < 0);
}
...@@ -4,19 +4,19 @@ ...@@ -4,19 +4,19 @@
static git_net_url source, target; static git_net_url source, target;
void test_network_joinpath__initialize(void) void test_network_url_joinpath__initialize(void)
{ {
memset(&source, 0, sizeof(source)); memset(&source, 0, sizeof(source));
memset(&target, 0, sizeof(target)); memset(&target, 0, sizeof(target));
} }
void test_network_joinpath__cleanup(void) void test_network_url_joinpath__cleanup(void)
{ {
git_net_url_dispose(&source); git_net_url_dispose(&source);
git_net_url_dispose(&target); git_net_url_dispose(&target);
} }
void test_network_joinpath__target_paths_and_queries(void) void test_network_url_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_parse(&source, "http://example.com/a/b"));
...@@ -31,7 +31,7 @@ void test_network_joinpath__target_paths_and_queries(void) ...@@ -31,7 +31,7 @@ void test_network_joinpath__target_paths_and_queries(void)
git_net_url_dispose(&target); git_net_url_dispose(&target);
} }
void test_network_joinpath__source_query_removed(void) void test_network_url_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_parse(&source, "http://example.com/a/b?query&one&two"));
...@@ -46,7 +46,7 @@ void test_network_joinpath__source_query_removed(void) ...@@ -46,7 +46,7 @@ void test_network_joinpath__source_query_removed(void)
git_net_url_dispose(&target); git_net_url_dispose(&target);
} }
void test_network_joinpath__source_lacks_path(void) void test_network_url_joinpath__source_lacks_path(void)
{ {
cl_git_pass(git_net_url_parse(&source, "http://example.com")); cl_git_pass(git_net_url_parse(&source, "http://example.com"));
...@@ -91,7 +91,7 @@ void test_network_joinpath__source_lacks_path(void) ...@@ -91,7 +91,7 @@ void test_network_joinpath__source_lacks_path(void)
git_net_url_dispose(&target); git_net_url_dispose(&target);
} }
void test_network_joinpath__source_is_slash(void) void test_network_url_joinpath__source_is_slash(void)
{ {
cl_git_pass(git_net_url_parse(&source, "http://example.com/")); cl_git_pass(git_net_url_parse(&source, "http://example.com/"));
...@@ -137,7 +137,7 @@ void test_network_joinpath__source_is_slash(void) ...@@ -137,7 +137,7 @@ void test_network_joinpath__source_is_slash(void)
} }
void test_network_joinpath__source_has_query(void) void test_network_url_joinpath__source_has_query(void)
{ {
cl_git_pass(git_net_url_parse(&source, "http://example.com?query")); cl_git_pass(git_net_url_parse(&source, "http://example.com?query"));
...@@ -183,7 +183,7 @@ void test_network_joinpath__source_has_query(void) ...@@ -183,7 +183,7 @@ void test_network_joinpath__source_has_query(void)
} }
void test_network_joinpath__empty_query_ignored(void) void test_network_url_joinpath__empty_query_ignored(void)
{ {
cl_git_pass(git_net_url_parse(&source, "http://example.com/foo")); cl_git_pass(git_net_url_parse(&source, "http://example.com/foo"));
......
#include "clar_libgit2.h"
#include "net.h"
struct url_pattern {
const char *url;
const char *pattern;
bool matches;
};
void test_network_url_pattern__single(void)
{
git_net_url url;
size_t i;
struct url_pattern url_patterns[] = {
/* Wildcard matches */
{ "https://example.com/", "", false },
{ "https://example.com/", "*", true },
/* Literal and wildcard matches */
{ "https://example.com/", "example.com", true },
{ "https://example.com/", ".example.com", true },
{ "https://example.com/", "*.example.com", true },
{ "https://www.example.com/", "www.example.com", true },
{ "https://www.example.com/", ".example.com", true },
{ "https://www.example.com/", "*.example.com", true },
/* Literal and wildcard failures */
{ "https://example.com/", "example.org", false },
{ "https://example.com/", ".example.org", false },
{ "https://example.com/", "*.example.org", false },
{ "https://foo.example.com/", "www.example.com", false },
/*
* A port in the pattern is optional; if no port is
* present, it matches *all* ports.
*/
{ "https://example.com/", "example.com:443", true },
{ "https://example.com/", "example.com:80", false },
{ "https://example.com:1443/", "example.com", true },
/* Failures with similar prefix/suffix */
{ "https://texample.com/", "example.com", false },
{ "https://example.com/", "mexample.com", false },
{ "https://example.com:44/", "example.com:443", false },
{ "https://example.com:443/", "example.com:44", false },
};
for (i = 0; i < ARRAY_SIZE(url_patterns); i++) {
cl_git_pass(git_net_url_parse(&url, url_patterns[i].url));
cl_assert_(git_net_url_matches_pattern(&url, url_patterns[i].pattern) == url_patterns[i].matches, url_patterns[i].pattern);
git_net_url_dispose(&url);
}
}
void test_network_url_pattern__list(void)
{
git_net_url url;
size_t i;
struct url_pattern url_patterns[] = {
/* Wildcard matches */
{ "https://example.com/", "", false },
{ "https://example.com/", "*", true },
{ "https://example.com/", ",example.com,", true },
{ "https://example.com/", "foo,,example.com,,bar", true },
{ "https://example.com/", "foo,,zzz,,*,,bar", true },
/* Literals */
{ "https://example.com/", "example.com", true },
{ "https://example.com/", "foo.bar,example.com", true },
{ "https://example.com/", "foo.bar", false },
{ "https://example.com/", "foo.bar,example.org", false },
{ "https://www.example.com/", "foo.example.com,www.example.com,bar.example.com", true },
{ "https://www.example.com/", "foo.example.com,baz.example.com,bar.example.com", false },
{ "https://foo.example.com/", "www.example.com", false },
{ "https://foo.example.com/", "bar.example.com,www.example.com,", false },
/* Wildcards */
{ "https://example.com/", ".example.com", true },
{ "https://example.com/", "*.example.com", true },
{ "https://example.com/", "foo.com,bar.com,.example.com", true },
{ "https://example.com/", ".foo.com,.bar.com,.example.com", true },
{ "https://example.com/", ".foo.com,.bar.com,asdf.com", false },
{ "https://example.com/", "*.foo,*.bar,*.example.com,*.asdf", true },
{ "https://example.com/", "*.foo,*.bar,*.asdf", false },
/* Ports! */
{ "https://example.com/", "example.com:443", true },
{ "https://example.com/", "example.com:42,example.com:443,example.com:99", true },
{ "https://example.com/", "example.com:42,example.com:80,example.org:443", false },
{ "https://example.com:1443/", "example.com", true },
{ "https://example.com:44/", "example.com:443", false },
{ "https://example.com:443/", "example.com:44", false },
};
for (i = 0; i < ARRAY_SIZE(url_patterns); i++) {
cl_git_pass(git_net_url_parse(&url, url_patterns[i].url));
cl_assert_(git_net_url_matches_pattern_list(&url, url_patterns[i].pattern) == url_patterns[i].matches, url_patterns[i].pattern);
git_net_url_dispose(&url);
}
}
...@@ -4,17 +4,17 @@ ...@@ -4,17 +4,17 @@
static git_net_url conndata; static git_net_url conndata;
void test_network_redirect__initialize(void) void test_network_url_redirect__initialize(void)
{ {
memset(&conndata, 0, sizeof(conndata)); memset(&conndata, 0, sizeof(conndata));
} }
void test_network_redirect__cleanup(void) void test_network_url_redirect__cleanup(void)
{ {
git_net_url_dispose(&conndata); git_net_url_dispose(&conndata);
} }
void test_network_redirect__redirect_http(void) void test_network_url_redirect__redirect_http(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, cl_git_pass(git_net_url_parse(&conndata,
"http://example.com/foo/bar/baz")); "http://example.com/foo/bar/baz"));
...@@ -28,7 +28,7 @@ void test_network_redirect__redirect_http(void) ...@@ -28,7 +28,7 @@ void test_network_redirect__redirect_http(void)
cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_p(conndata.password, NULL);
} }
void test_network_redirect__redirect_ssl(void) void test_network_url_redirect__redirect_ssl(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, cl_git_pass(git_net_url_parse(&conndata,
"https://example.com/foo/bar/baz")); "https://example.com/foo/bar/baz"));
...@@ -42,7 +42,7 @@ void test_network_redirect__redirect_ssl(void) ...@@ -42,7 +42,7 @@ void test_network_redirect__redirect_ssl(void)
cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_p(conndata.password, NULL);
} }
void test_network_redirect__redirect_leaves_root_path(void) void test_network_url_redirect__redirect_leaves_root_path(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, cl_git_pass(git_net_url_parse(&conndata,
"https://example.com/foo/bar/baz")); "https://example.com/foo/bar/baz"));
...@@ -56,7 +56,7 @@ void test_network_redirect__redirect_leaves_root_path(void) ...@@ -56,7 +56,7 @@ void test_network_redirect__redirect_leaves_root_path(void)
cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_p(conndata.password, NULL);
} }
void test_network_redirect__redirect_encoded_username_password(void) void test_network_url_redirect__redirect_encoded_username_password(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, cl_git_pass(git_net_url_parse(&conndata,
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz")); "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
...@@ -70,7 +70,7 @@ void test_network_redirect__redirect_encoded_username_password(void) ...@@ -70,7 +70,7 @@ void test_network_redirect__redirect_encoded_username_password(void)
cl_assert_equal_s(conndata.password, "pass@word%zyx%v"); cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
} }
void test_network_redirect__redirect_cross_host_denied(void) void test_network_url_redirect__redirect_cross_host_denied(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz")); cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
cl_git_fail_with(git_net_url_apply_redirect(&conndata, cl_git_fail_with(git_net_url_apply_redirect(&conndata,
...@@ -78,7 +78,7 @@ void test_network_redirect__redirect_cross_host_denied(void) ...@@ -78,7 +78,7 @@ void test_network_redirect__redirect_cross_host_denied(void)
-1); -1);
} }
void test_network_redirect__redirect_http_downgrade_denied(void) void test_network_url_redirect__redirect_http_downgrade_denied(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz")); cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
cl_git_fail_with(git_net_url_apply_redirect(&conndata, cl_git_fail_with(git_net_url_apply_redirect(&conndata,
...@@ -86,7 +86,7 @@ void test_network_redirect__redirect_http_downgrade_denied(void) ...@@ -86,7 +86,7 @@ void test_network_redirect__redirect_http_downgrade_denied(void)
-1); -1);
} }
void test_network_redirect__redirect_relative(void) void test_network_url_redirect__redirect_relative(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff")); cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
cl_git_pass(git_net_url_apply_redirect(&conndata, cl_git_pass(git_net_url_apply_redirect(&conndata,
...@@ -99,7 +99,7 @@ void test_network_redirect__redirect_relative(void) ...@@ -99,7 +99,7 @@ void test_network_redirect__redirect_relative(void)
cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_p(conndata.password, NULL);
} }
void test_network_redirect__redirect_relative_ssl(void) void test_network_url_redirect__redirect_relative_ssl(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff")); cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
cl_git_pass(git_net_url_apply_redirect(&conndata, cl_git_pass(git_net_url_apply_redirect(&conndata,
...@@ -112,7 +112,7 @@ void test_network_redirect__redirect_relative_ssl(void) ...@@ -112,7 +112,7 @@ void test_network_redirect__redirect_relative_ssl(void)
cl_assert_equal_p(conndata.password, NULL); cl_assert_equal_p(conndata.password, NULL);
} }
void test_network_redirect__service_query_no_query_params_in_location(void) void test_network_url_redirect__service_query_no_query_params_in_location(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack")); cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
cl_git_pass(git_net_url_apply_redirect(&conndata, cl_git_pass(git_net_url_apply_redirect(&conndata,
...@@ -120,7 +120,7 @@ void test_network_redirect__service_query_no_query_params_in_location(void) ...@@ -120,7 +120,7 @@ void test_network_redirect__service_query_no_query_params_in_location(void)
cl_assert_equal_s(conndata.path, "/baz"); cl_assert_equal_s(conndata.path, "/baz");
} }
void test_network_redirect__service_query_with_query_params_in_location(void) void test_network_url_redirect__service_query_with_query_params_in_location(void)
{ {
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack")); cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
cl_git_pass(git_net_url_apply_redirect(&conndata, cl_git_pass(git_net_url_apply_redirect(&conndata,
......
...@@ -36,6 +36,7 @@ static char *_remote_expectcontinue = NULL; ...@@ -36,6 +36,7 @@ static char *_remote_expectcontinue = NULL;
static int _orig_proxies_need_reset = 0; static int _orig_proxies_need_reset = 0;
static char *_orig_http_proxy = NULL; static char *_orig_http_proxy = NULL;
static char *_orig_https_proxy = NULL; static char *_orig_https_proxy = NULL;
static char *_orig_no_proxy = NULL;
static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload) static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload)
{ {
...@@ -110,9 +111,11 @@ void test_online_clone__cleanup(void) ...@@ -110,9 +111,11 @@ void test_online_clone__cleanup(void)
if (_orig_proxies_need_reset) { if (_orig_proxies_need_reset) {
cl_setenv("HTTP_PROXY", _orig_http_proxy); cl_setenv("HTTP_PROXY", _orig_http_proxy);
cl_setenv("HTTPS_PROXY", _orig_https_proxy); cl_setenv("HTTPS_PROXY", _orig_https_proxy);
cl_setenv("NO_PROXY", _orig_no_proxy);
git__free(_orig_http_proxy); git__free(_orig_http_proxy);
git__free(_orig_https_proxy); git__free(_orig_https_proxy);
git__free(_orig_no_proxy);
} }
git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL); git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL);
...@@ -854,6 +857,7 @@ void test_online_clone__proxy_credentials_in_environment(void) ...@@ -854,6 +857,7 @@ void test_online_clone__proxy_credentials_in_environment(void)
_orig_http_proxy = cl_getenv("HTTP_PROXY"); _orig_http_proxy = cl_getenv("HTTP_PROXY");
_orig_https_proxy = cl_getenv("HTTPS_PROXY"); _orig_https_proxy = cl_getenv("HTTPS_PROXY");
_orig_no_proxy = cl_getenv("NO_PROXY");
_orig_proxies_need_reset = 1; _orig_proxies_need_reset = 1;
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
...@@ -865,6 +869,7 @@ void test_online_clone__proxy_credentials_in_environment(void) ...@@ -865,6 +869,7 @@ void test_online_clone__proxy_credentials_in_environment(void)
cl_setenv("HTTP_PROXY", url.ptr); cl_setenv("HTTP_PROXY", url.ptr);
cl_setenv("HTTPS_PROXY", url.ptr); cl_setenv("HTTPS_PROXY", url.ptr);
cl_setenv("NO_PROXY", NULL);
cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
......
#include "clar_libgit2.h"
#include "remote.h"
#include "net.h"
static git_repository *repo;
static git_net_url url = GIT_NET_URL_INIT;
static int orig_proxies_need_reset = 0;
static char *orig_http_proxy = NULL;
static char *orig_https_proxy = NULL;
static char *orig_no_proxy = NULL;
void test_remote_httpproxy__initialize(void)
{
git_remote *remote;
repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_remote_create(&remote, repo, "lg2", "https://github.com/libgit2/libgit2"));
cl_git_pass(git_net_url_parse(&url, "https://github.com/libgit2/libgit2"));
git_remote_free(remote);
orig_proxies_need_reset = 0;
}
void test_remote_httpproxy__cleanup(void)
{
if (orig_proxies_need_reset) {
cl_setenv("HTTP_PROXY", orig_http_proxy);
cl_setenv("HTTPS_PROXY", orig_https_proxy);
cl_setenv("NO_PROXY", orig_no_proxy);
git__free(orig_http_proxy);
git__free(orig_https_proxy);
git__free(orig_no_proxy);
}
git_net_url_dispose(&url);
cl_git_sandbox_cleanup();
}
void assert_proxy_is(const char *expected)
{
git_remote *remote;
char *proxy;
cl_git_pass(git_remote_lookup(&remote, repo, "lg2"));
cl_git_pass(git_remote__http_proxy(&proxy, remote, &url));
if (expected)
cl_assert_equal_s(proxy, expected);
else
cl_assert_equal_p(proxy, expected);
git_remote_free(remote);
git__free(proxy);
}
void assert_config_match(const char *config, const char *expected)
{
git_remote *remote;
char *proxy;
if (config)
cl_repo_set_string(repo, config, expected);
cl_git_pass(git_remote_lookup(&remote, repo, "lg2"));
cl_git_pass(git_remote__http_proxy(&proxy, remote, &url));
if (expected)
cl_assert_equal_s(proxy, expected);
else
cl_assert_equal_p(proxy, expected);
git_remote_free(remote);
git__free(proxy);
}
void test_remote_httpproxy__config_overrides(void)
{
/*
* http.proxy should be honored, then http.<url>.proxy should
* be honored in increasing specificity of the url. finally,
* remote.<name>.proxy is the most specific.
*/
assert_config_match(NULL, NULL);
assert_config_match("http.proxy", "http://localhost:1/");
assert_config_match("http.https://github.com.proxy", "http://localhost:2/");
assert_config_match("http.https://github.com/.proxy", "http://localhost:3/");
assert_config_match("http.https://github.com/libgit2.proxy", "http://localhost:4/");
assert_config_match("http.https://github.com/libgit2/.proxy", "http://localhost:5/");
assert_config_match("http.https://github.com/libgit2/libgit2.proxy", "http://localhost:6/");
assert_config_match("remote.lg2.proxy", "http://localhost:7/");
}
void test_remote_httpproxy__config_empty_overrides(void)
{
/*
* with greater specificity, an empty config entry overrides
* a set one
*/
assert_config_match("http.proxy", "http://localhost:1/");
assert_config_match("http.https://github.com.proxy", "");
assert_config_match("http.https://github.com/libgit2/libgit2.proxy", "http://localhost:2/");
assert_config_match("remote.lg2.proxy", "");
}
void test_remote_httpproxy__env(void)
{
orig_http_proxy = cl_getenv("HTTP_PROXY");
orig_https_proxy = cl_getenv("HTTPS_PROXY");
orig_no_proxy = cl_getenv("NO_PROXY");
orig_proxies_need_reset = 1;
/* HTTP proxy is ignored for HTTPS */
cl_setenv("HTTP_PROXY", "http://localhost:9/");
assert_proxy_is(NULL);
/* HTTPS proxy is honored for HTTPS */
cl_setenv("HTTPS_PROXY", "http://localhost:10/");
assert_proxy_is("http://localhost:10/");
/* NO_PROXY is honored */
cl_setenv("NO_PROXY", "github.com:443");
assert_proxy_is(NULL);
cl_setenv("NO_PROXY", "github.com:80");
assert_proxy_is("http://localhost:10/");
cl_setenv("NO_PROXY", "github.com");
assert_proxy_is(NULL);
cl_setenv("NO_PROXY", "github.dev,github.com,github.foo");
assert_proxy_is(NULL);
/* configuration overrides environment variables */
cl_setenv("NO_PROXY", "github.none");
assert_config_match("http.https://github.com.proxy", "http://localhost:11/");
}
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