summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2021-09-01 21:57:16 -0400
committerGitHub <noreply@github.com>2021-09-01 21:57:16 -0400
commit002b2ffe69d9d17e5b5570c5cd3cc13bac4b004c (patch)
tree1ae5a9dd0aab3ffec9d7433efff5b97696db9b9d
parentd56b4079e0474b2f96abe0487a44359970e43c2a (diff)
parent3c0f14cc95debb426bd53150aac0eef1a7f625d8 (diff)
downloadlibgit2-002b2ffe69d9d17e5b5570c5cd3cc13bac4b004c.tar.gz
Merge pull request #6026 from libgit2/ethomson/proxy
Update proxy configuration
-rw-r--r--src/net.c114
-rw-r--r--src/net.h11
-rw-r--r--src/remote.c149
-rw-r--r--src/remote.h3
-rw-r--r--src/transports/http.c4
-rw-r--r--src/transports/winhttp.c4
-rw-r--r--src/util.h11
-rw-r--r--tests/core/string.c11
-rw-r--r--tests/network/url/joinpath.c (renamed from tests/network/joinpath.c)16
-rw-r--r--tests/network/url/parse.c (renamed from tests/network/urlparse.c)78
-rw-r--r--tests/network/url/pattern.c103
-rw-r--r--tests/network/url/redirect.c (renamed from tests/network/redirect.c)24
-rw-r--r--tests/online/clone.c5
-rw-r--r--tests/remote/httpproxy.c139
14 files changed, 565 insertions, 107 deletions
diff --git a/src/net.c b/src/net.c
index d4a9f8a6d..a685e4893 100644
--- a/src/net.c
+++ b/src/net.c
@@ -35,6 +35,46 @@ static const char *default_port_for_scheme(const char *scheme)
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)
{
struct http_parser_url u = {0};
@@ -404,6 +444,80 @@ int git_net_url_fmt_path(git_buf *buf, git_net_url *url)
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)
{
if (url->username)
diff --git a/src/net.h b/src/net.h
index 391b99a9f..322d0bda9 100644
--- a/src/net.h
+++ b/src/net.h
@@ -21,6 +21,9 @@ typedef struct git_net_url {
#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. */
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);
/** Place the path and query string into the given buffer. */
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. */
extern void git_net_url_dispose(git_net_url *url);
diff --git a/src/remote.c b/src/remote.c
index 73375b352..7dddea93a 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -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);
}
-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_buf val = GIT_BUF_INIT;
int error;
- GIT_ASSERT_ARG(remote);
+ if ((error = git_config__lookup_entry(&ce, cfg, name, false)) < 0)
+ return error;
- if (!proxy_url || !remote->repo)
- return -1;
+ if (ce && ce->value) {
+ *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)
- return error;
+ if (url->path[len - 1] == '/') {
+ len--;
+ } else {
+ while (len && url->path[len - 1] != '/')
+ len--;
+ }
- /* Go through the possible sources for proxy configuration, from most specific
- * to least specific. */
+ url->path[len] = '\0';
+}
+
+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 */
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)
- return error;
+ if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0 ||
+ (error = lookup_config(out, cfg, buf.ptr)) != GIT_ENOTFOUND)
+ goto done;
+ }
- error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
- git_buf_dispose(&buf);
+ while (true) {
+ git_buf_clear(&buf);
- if (error < 0)
- return error;
+ if ((error = git_buf_puts(&buf, "http.")) < 0 ||
+ (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) {
- *proxy_url = git__strdup(ce->value);
- goto found;
- }
+ if (! lookup_url.path[0])
+ break;
+
+ url_config_trim(&lookup_url);
}
- /* http.proxy config setting */
- if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
- return error;
+ git_buf_clear(&buf);
- if (ce && ce->value) {
- *proxy_url = git__strdup(ce->value);
- goto found;
- }
+ error = lookup_config(out, cfg, "http.proxy");
+
+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 */
- 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 */
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 == GIT_ENOTFOUND) {
- git_error_clear();
- error = 0;
- }
+ if (error)
+ goto done;
- 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:
- GIT_ERROR_CHECK_ALLOC(*proxy_url);
- git_config_entry_free(ce);
+ if (error && error != GIT_ENOTFOUND)
+ goto done;
+
+ 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;
}
diff --git a/src/remote.h b/src/remote.h
index df75ed359..ce92db76a 100644
--- a/src/remote.h
+++ b/src/remote.h
@@ -15,6 +15,7 @@
#include "refspec.h"
#include "vector.h"
+#include "net.h"
#define GIT_REMOTE_ORIGIN "origin"
@@ -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__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_dst_refspec(git_remote *remote, const char *refname);
diff --git a/src/transports/http.c b/src/transports/http.c
index 691bceb75..914335aba 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -290,7 +290,6 @@ static int lookup_proxy(
{
const char *proxy;
git_remote *remote;
- bool use_ssl;
char *config = NULL;
int error = 0;
@@ -304,9 +303,8 @@ static int lookup_proxy(
case GIT_PROXY_AUTO:
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)
goto done;
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index ea2195a99..178773a41 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -429,7 +429,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
proxy_opts = &t->owner->proxy;
if (proxy_opts->type == GIT_PROXY_AUTO) {
/* 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;
}
else if (proxy_opts->type == GIT_PROXY_SPECIFIED) {
@@ -742,7 +742,7 @@ static void CALLBACK winhttp_status(
git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
break;
-
+
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
((winhttp_stream *) ctx)->status_sending_request_reached = 1;
diff --git a/src/util.h b/src/util.h
index a7735366b..68c2b1804 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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);
+/*
+ * 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 {
git_atomic32 refcount;
void *owner;
diff --git a/tests/core/string.c b/tests/core/string.c
index 85db0c662..928dfbcc1 100644
--- a/tests/core/string.c
+++ b/tests/core/string.c
@@ -123,3 +123,14 @@ void test_core_string__strcasecmp(void)
cl_assert(git__strcasecmp("et", "e\342\202\254ghi=") < 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);
+}
diff --git a/tests/network/joinpath.c b/tests/network/url/joinpath.c
index da8393b91..bf4557138 100644
--- a/tests/network/joinpath.c
+++ b/tests/network/url/joinpath.c
@@ -4,19 +4,19 @@
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(&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(&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"));
@@ -31,7 +31,7 @@ void test_network_joinpath__target_paths_and_queries(void)
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"));
@@ -46,7 +46,7 @@ void test_network_joinpath__source_query_removed(void)
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"));
@@ -91,7 +91,7 @@ void test_network_joinpath__source_lacks_path(void)
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/"));
@@ -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"));
@@ -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"));
diff --git a/tests/network/urlparse.c b/tests/network/url/parse.c
index 91c1a527c..edfd6abec 100644
--- a/tests/network/urlparse.c
+++ b/tests/network/url/parse.c
@@ -3,19 +3,19 @@
static git_net_url conndata;
-void test_network_urlparse__initialize(void)
+void test_network_url_parse__initialize(void)
{
memset(&conndata, 0, sizeof(conndata));
}
-void test_network_urlparse__cleanup(void)
+void test_network_url_parse__cleanup(void)
{
git_net_url_dispose(&conndata);
}
/* Hostname */
-void test_network_urlparse__hostname_trivial(void)
+void test_network_url_parse__hostname_trivial(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -27,7 +27,7 @@ void test_network_urlparse__hostname_trivial(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_root(void)
+void test_network_url_parse__hostname_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com/"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -39,7 +39,7 @@ void test_network_urlparse__hostname_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_implied_root(void)
+void test_network_url_parse__hostname_implied_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -51,7 +51,7 @@ void test_network_urlparse__hostname_implied_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_implied_root_custom_port(void)
+void test_network_url_parse__hostname_implied_root_custom_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com:42"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -63,7 +63,7 @@ void test_network_urlparse__hostname_implied_root_custom_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__hostname_implied_root_empty_port(void)
+void test_network_url_parse__hostname_implied_root_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com:"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -75,7 +75,7 @@ void test_network_urlparse__hostname_implied_root_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_encoded_password(void)
+void test_network_url_parse__hostname_encoded_password(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass%2fis%40bad@hostname.com:1234/"));
@@ -88,7 +88,7 @@ void test_network_urlparse__hostname_encoded_password(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__hostname_user(void)
+void test_network_url_parse__hostname_user(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user@example.com/resource"));
@@ -101,7 +101,7 @@ void test_network_urlparse__hostname_user(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_user_pass(void)
+void test_network_url_parse__hostname_user_pass(void)
{
/* user:pass@hostname.tld/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -115,7 +115,7 @@ void test_network_urlparse__hostname_user_pass(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_port(void)
+void test_network_url_parse__hostname_port(void)
{
/* hostname.tld:port/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -129,7 +129,7 @@ void test_network_urlparse__hostname_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__hostname_empty_port(void)
+void test_network_url_parse__hostname_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com:/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -141,7 +141,7 @@ void test_network_urlparse__hostname_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__hostname_user_port(void)
+void test_network_url_parse__hostname_user_port(void)
{
/* user@hostname.tld:port/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -155,7 +155,7 @@ void test_network_urlparse__hostname_user_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__hostname_user_pass_port(void)
+void test_network_url_parse__hostname_user_pass_port(void)
{
/* user:pass@hostname.tld:port/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -171,7 +171,7 @@ void test_network_urlparse__hostname_user_pass_port(void)
/* IPv4 addresses */
-void test_network_urlparse__ipv4_trivial(void)
+void test_network_url_parse__ipv4_trivial(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -183,7 +183,7 @@ void test_network_urlparse__ipv4_trivial(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_root(void)
+void test_network_url_parse__ipv4_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -195,7 +195,7 @@ void test_network_urlparse__ipv4_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_implied_root(void)
+void test_network_url_parse__ipv4_implied_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -207,7 +207,7 @@ void test_network_urlparse__ipv4_implied_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_implied_root_custom_port(void)
+void test_network_url_parse__ipv4_implied_root_custom_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:42"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -219,7 +219,7 @@ void test_network_urlparse__ipv4_implied_root_custom_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv4_implied_root_empty_port(void)
+void test_network_url_parse__ipv4_implied_root_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -231,7 +231,7 @@ void test_network_urlparse__ipv4_implied_root_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_encoded_password(void)
+void test_network_url_parse__ipv4_encoded_password(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass%2fis%40bad@192.168.1.1:1234/"));
@@ -244,7 +244,7 @@ void test_network_urlparse__ipv4_encoded_password(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv4_user(void)
+void test_network_url_parse__ipv4_user(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user@192.168.1.1/resource"));
@@ -257,7 +257,7 @@ void test_network_urlparse__ipv4_user(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_user_pass(void)
+void test_network_url_parse__ipv4_user_pass(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass@192.168.1.1/resource"));
@@ -270,7 +270,7 @@ void test_network_urlparse__ipv4_user_pass(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_port(void)
+void test_network_url_parse__ipv4_port(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://192.168.1.1:9191/resource"));
@@ -283,7 +283,7 @@ void test_network_urlparse__ipv4_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv4_empty_port(void)
+void test_network_url_parse__ipv4_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -295,7 +295,7 @@ void test_network_urlparse__ipv4_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv4_user_port(void)
+void test_network_url_parse__ipv4_user_port(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user@192.168.1.1:9191/resource"));
@@ -308,7 +308,7 @@ void test_network_urlparse__ipv4_user_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv4_user_pass_port(void)
+void test_network_url_parse__ipv4_user_pass_port(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass@192.168.1.1:9191/resource"));
@@ -323,7 +323,7 @@ void test_network_urlparse__ipv4_user_pass_port(void)
/* IPv6 addresses */
-void test_network_urlparse__ipv6_trivial(void)
+void test_network_url_parse__ipv6_trivial(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -335,7 +335,7 @@ void test_network_urlparse__ipv6_trivial(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_root(void)
+void test_network_url_parse__ipv6_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -347,7 +347,7 @@ void test_network_urlparse__ipv6_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_implied_root(void)
+void test_network_url_parse__ipv6_implied_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -359,7 +359,7 @@ void test_network_urlparse__ipv6_implied_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_implied_root_custom_port(void)
+void test_network_url_parse__ipv6_implied_root_custom_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:42"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -371,7 +371,7 @@ void test_network_urlparse__ipv6_implied_root_custom_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv6_implied_root_empty_port(void)
+void test_network_url_parse__ipv6_implied_root_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -383,7 +383,7 @@ void test_network_urlparse__ipv6_implied_root_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_encoded_password(void)
+void test_network_url_parse__ipv6_encoded_password(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001]:1234/"));
@@ -396,7 +396,7 @@ void test_network_urlparse__ipv6_encoded_password(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv6_user(void)
+void test_network_url_parse__ipv6_user(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user@[fe80::dcad:beff:fe00:0001]/resource"));
@@ -409,7 +409,7 @@ void test_network_urlparse__ipv6_user(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_user_pass(void)
+void test_network_url_parse__ipv6_user_pass(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass@[fe80::dcad:beff:fe00:0001]/resource"));
@@ -422,7 +422,7 @@ void test_network_urlparse__ipv6_user_pass(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_port(void)
+void test_network_url_parse__ipv6_port(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://[fe80::dcad:beff:fe00:0001]:9191/resource"));
@@ -435,7 +435,7 @@ void test_network_urlparse__ipv6_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv6_empty_port(void)
+void test_network_url_parse__ipv6_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -447,7 +447,7 @@ void test_network_urlparse__ipv6_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__ipv6_user_port(void)
+void test_network_url_parse__ipv6_user_port(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user@[fe80::dcad:beff:fe00:0001]:9191/resource"));
@@ -460,7 +460,7 @@ void test_network_urlparse__ipv6_user_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv6_user_pass_port(void)
+void test_network_url_parse__ipv6_user_pass_port(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass@[fe80::dcad:beff:fe00:0001]:9191/resource"));
@@ -473,7 +473,7 @@ void test_network_urlparse__ipv6_user_pass_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__ipv6_invalid_addresses(void)
+void test_network_url_parse__ipv6_invalid_addresses(void)
{
/* Opening bracket missing */
cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
diff --git a/tests/network/url/pattern.c b/tests/network/url/pattern.c
new file mode 100644
index 000000000..5e4495f70
--- /dev/null
+++ b/tests/network/url/pattern.c
@@ -0,0 +1,103 @@
+#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);
+ }
+}
diff --git a/tests/network/redirect.c b/tests/network/url/redirect.c
index 7ce1310db..2c0b614d9 100644
--- a/tests/network/redirect.c
+++ b/tests/network/url/redirect.c
@@ -4,17 +4,17 @@
static git_net_url conndata;
-void test_network_redirect__initialize(void)
+void test_network_url_redirect__initialize(void)
{
memset(&conndata, 0, sizeof(conndata));
}
-void test_network_redirect__cleanup(void)
+void test_network_url_redirect__cleanup(void)
{
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,
"http://example.com/foo/bar/baz"));
@@ -28,7 +28,7 @@ void test_network_redirect__redirect_http(void)
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,
"https://example.com/foo/bar/baz"));
@@ -42,7 +42,7 @@ void test_network_redirect__redirect_ssl(void)
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,
"https://example.com/foo/bar/baz"));
@@ -56,7 +56,7 @@ void test_network_redirect__redirect_leaves_root_path(void)
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,
"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)
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_fail_with(git_net_url_apply_redirect(&conndata,
@@ -78,7 +78,7 @@ void test_network_redirect__redirect_cross_host_denied(void)
-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_fail_with(git_net_url_apply_redirect(&conndata,
@@ -86,7 +86,7 @@ void test_network_redirect__redirect_http_downgrade_denied(void)
-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_apply_redirect(&conndata,
@@ -99,7 +99,7 @@ void test_network_redirect__redirect_relative(void)
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_apply_redirect(&conndata,
@@ -112,7 +112,7 @@ void test_network_redirect__redirect_relative_ssl(void)
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_apply_redirect(&conndata,
@@ -120,7 +120,7 @@ void test_network_redirect__service_query_no_query_params_in_location(void)
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_apply_redirect(&conndata,
diff --git a/tests/online/clone.c b/tests/online/clone.c
index dbf45dcb3..7d43c6a09 100644
--- a/tests/online/clone.c
+++ b/tests/online/clone.c
@@ -36,6 +36,7 @@ static char *_remote_expectcontinue = NULL;
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;
static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload)
{
@@ -110,9 +111,11 @@ void test_online_clone__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_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL);
@@ -854,6 +857,7 @@ void test_online_clone__proxy_credentials_in_environment(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;
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
@@ -865,6 +869,7 @@ void test_online_clone__proxy_credentials_in_environment(void)
cl_setenv("HTTP_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));
diff --git a/tests/remote/httpproxy.c b/tests/remote/httpproxy.c
new file mode 100644
index 000000000..097db4cd5
--- /dev/null
+++ b/tests/remote/httpproxy.c
@@ -0,0 +1,139 @@
+#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/");
+}