summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2020-12-23 12:32:58 +0000
committerGitHub <noreply@github.com>2020-12-23 12:32:58 +0000
commitfe41e5823986aff01054b7db4b869b2896ea4c30 (patch)
treea0e5ca132d68d0216a9f8de824a9f7a865127e9b
parent1c3f29a9e21e494d19fbe6e5f965fce8bd2b7d48 (diff)
parent27301cd02676e8e1247f36ff5bbd3ee9c2579ee1 (diff)
downloadlibgit2-fe41e5823986aff01054b7db4b869b2896ea4c30.tar.gz
Merge pull request #5741 from libgit2/ethomson/ipv6
Handle ipv6 addresses
-rw-r--r--src/net.c7
-rw-r--r--src/net.h7
-rw-r--r--src/transports/httpclient.c40
-rw-r--r--src/transports/winhttp.c42
-rw-r--r--tests/network/urlparse.c413
5 files changed, 469 insertions, 40 deletions
diff --git a/src/net.c b/src/net.c
index 0705dd390..d4a9f8a6d 100644
--- a/src/net.c
+++ b/src/net.c
@@ -335,7 +335,7 @@ bool git_net_url_valid(git_net_url *url)
return (url->host && url->port && url->path);
}
-int git_net_url_is_default_port(git_net_url *url)
+bool git_net_url_is_default_port(git_net_url *url)
{
const char *default_port;
@@ -345,6 +345,11 @@ int git_net_url_is_default_port(git_net_url *url)
return false;
}
+bool git_net_url_is_ipv6(git_net_url *url)
+{
+ return (strchr(url->host, ':') != NULL);
+}
+
void git_net_url_swap(git_net_url *a, git_net_url *b)
{
git_net_url tmp = GIT_NET_URL_INIT;
diff --git a/src/net.h b/src/net.h
index 7e72db13f..391b99a9f 100644
--- a/src/net.h
+++ b/src/net.h
@@ -33,8 +33,11 @@ extern int git_net_url_joinpath(
/** Ensures that a URL is minimally valid (contains a host, port and path) */
extern bool git_net_url_valid(git_net_url *url);
-/** Returns nonzero if the URL is on the default port. */
-extern int git_net_url_is_default_port(git_net_url *url);
+/** Returns true if the URL is on the default port. */
+extern bool git_net_url_is_default_port(git_net_url *url);
+
+/** Returns true if the host portion of the URL is an ipv6 address. */
+extern bool git_net_url_is_ipv6(git_net_url *url);
/* Applies a redirect to the URL with a git-aware service suffix. */
extern int git_net_url_apply_redirect(
diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c
index d9cbf1783..d3975746b 100644
--- a/src/transports/httpclient.c
+++ b/src/transports/httpclient.c
@@ -631,6 +631,26 @@ GIT_INLINE(int) apply_proxy_credentials(
request->proxy_credentials);
}
+static int puts_host_and_port(git_buf *buf, git_net_url *url, bool force_port)
+{
+ bool ipv6 = git_net_url_is_ipv6(url);
+
+ if (ipv6)
+ git_buf_putc(buf, '[');
+
+ git_buf_puts(buf, url->host);
+
+ if (ipv6)
+ git_buf_putc(buf, ']');
+
+ if (force_port || !git_net_url_is_default_port(url)) {
+ git_buf_putc(buf, ':');
+ git_buf_puts(buf, url->port);
+ }
+
+ return git_buf_oom(buf) ? -1 : 0;
+}
+
static int generate_connect_request(
git_http_client *client,
git_http_request *request)
@@ -641,14 +661,17 @@ static int generate_connect_request(
git_buf_clear(&client->request_msg);
buf = &client->request_msg;
- git_buf_printf(buf, "CONNECT %s:%s HTTP/1.1\r\n",
- client->server.url.host, client->server.url.port);
+ git_buf_puts(buf, "CONNECT ");
+ puts_host_and_port(buf, &client->server.url, true);
+ git_buf_puts(buf, " HTTP/1.1\r\n");
git_buf_puts(buf, "User-Agent: ");
git_http__user_agent(buf);
git_buf_puts(buf, "\r\n");
- git_buf_printf(buf, "Host: %s\r\n", client->proxy.url.host);
+ git_buf_puts(buf, "Host: ");
+ puts_host_and_port(buf, &client->proxy.url, false);
+ git_buf_puts(buf, "\r\n");
if ((error = apply_proxy_credentials(buf, client, request) < 0))
return -1;
@@ -687,11 +710,8 @@ static int generate_request(
git_http__user_agent(buf);
git_buf_puts(buf, "\r\n");
- git_buf_printf(buf, "Host: %s", request->url->host);
-
- if (!git_net_url_is_default_port(request->url))
- git_buf_printf(buf, ":%s", request->url->port);
-
+ git_buf_puts(buf, "Host: ");
+ puts_host_and_port(buf, request->url, false);
git_buf_puts(buf, "\r\n");
if (request->accept)
@@ -902,7 +922,7 @@ static int proxy_connect(
int error;
if (!client->proxy_connected || !client->keepalive) {
- git_trace(GIT_TRACE_DEBUG, "Connecting to proxy %s:%s",
+ git_trace(GIT_TRACE_DEBUG, "Connecting to proxy %s port %s",
client->proxy.url.host, client->proxy.url.port);
if ((error = server_create_stream(&client->proxy)) < 0 ||
@@ -1023,7 +1043,7 @@ static int http_client_connect(
goto on_error;
}
- git_trace(GIT_TRACE_DEBUG, "Connecting to remote %s:%s",
+ git_trace(GIT_TRACE_DEBUG, "Connecting to remote %s port %s",
client->server.url.host, client->server.url.port);
if ((error = server_connect(client)) < 0)
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index c82c788ae..54aacdba3 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -451,8 +451,14 @@ static int winhttp_stream_connect(winhttp_stream *s)
git_buf_puts(&processed_url, t->proxy.url.scheme);
git_buf_PUTS(&processed_url, "://");
+ if (git_net_url_is_ipv6(&t->proxy.url))
+ git_buf_putc(&processed_url, '[');
+
git_buf_puts(&processed_url, t->proxy.url.host);
+ if (git_net_url_is_ipv6(&t->proxy.url))
+ git_buf_putc(&processed_url, ']');
+
if (!git_net_url_is_default_port(&t->proxy.url))
git_buf_printf(&processed_url, ":%s", t->proxy.url.port);
@@ -736,10 +742,11 @@ static void CALLBACK winhttp_status(
static int winhttp_connect(
winhttp_subtransport *t)
{
- wchar_t *wide_host;
+ wchar_t *wide_host = NULL;
int32_t port;
- wchar_t *wide_ua;
- git_buf ua = GIT_BUF_INIT;
+ wchar_t *wide_ua = NULL;
+ git_buf ipv6 = GIT_BUF_INIT, ua = GIT_BUF_INIT;
+ const char *host;
int error = -1;
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
@@ -755,29 +762,33 @@ static int winhttp_connect(
/* Prepare port */
if (git__strntol32(&port, t->server.url.port,
strlen(t->server.url.port), NULL, 10) < 0)
- return -1;
+ goto on_error;
+
+ /* IPv6? Add braces around the host. */
+ if (git_net_url_is_ipv6(&t->server.url)) {
+ if (git_buf_printf(&ipv6, "[%s]", t->server.url.host) < 0)
+ goto on_error;
+
+ host = ipv6.ptr;
+ } else {
+ host = t->server.url.host;
+ }
/* Prepare host */
- if (git__utf8_to_16_alloc(&wide_host, t->server.url.host) < 0) {
+ if (git__utf8_to_16_alloc(&wide_host, host) < 0) {
git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
- return -1;
+ goto on_error;
}
- if ((error = git_http__user_agent(&ua)) < 0) {
- git__free(wide_host);
- return error;
- }
+ if (git_http__user_agent(&ua) < 0)
+ goto on_error;
if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
- git__free(wide_host);
- git_buf_dispose(&ua);
- return -1;
+ goto on_error;
}
- git_buf_dispose(&ua);
-
/* Establish session */
t->session = WinHttpOpen(
wide_ua,
@@ -836,6 +847,7 @@ on_error:
if (error < 0)
winhttp_close_connection(t);
+ git_buf_dispose(&ipv6);
git__free(wide_host);
git__free(wide_ua);
diff --git a/tests/network/urlparse.c b/tests/network/urlparse.c
index 15707885a..91c1a527c 100644
--- a/tests/network/urlparse.c
+++ b/tests/network/urlparse.c
@@ -13,7 +13,9 @@ void test_network_urlparse__cleanup(void)
git_net_url_dispose(&conndata);
}
-void test_network_urlparse__trivial(void)
+/* Hostname */
+
+void test_network_urlparse__hostname_trivial(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -25,7 +27,7 @@ void test_network_urlparse__trivial(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__root(void)
+void test_network_urlparse__hostname_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com/"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -37,7 +39,7 @@ void test_network_urlparse__root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__implied_root(void)
+void test_network_urlparse__hostname_implied_root(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -49,7 +51,7 @@ void test_network_urlparse__implied_root(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__implied_root_custom_port(void)
+void test_network_urlparse__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");
@@ -61,7 +63,7 @@ void test_network_urlparse__implied_root_custom_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__implied_root_empty_port(void)
+void test_network_urlparse__hostname_implied_root_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com:"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -73,7 +75,7 @@ void test_network_urlparse__implied_root_empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__encoded_password(void)
+void test_network_urlparse__hostname_encoded_password(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user:pass%2fis%40bad@hostname.com:1234/"));
@@ -86,7 +88,7 @@ void test_network_urlparse__encoded_password(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__user(void)
+void test_network_urlparse__hostname_user(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user@example.com/resource"));
@@ -99,7 +101,7 @@ void test_network_urlparse__user(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__user_pass(void)
+void test_network_urlparse__hostname_user_pass(void)
{
/* user:pass@hostname.tld/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -113,7 +115,7 @@ void test_network_urlparse__user_pass(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__port(void)
+void test_network_urlparse__hostname_port(void)
{
/* hostname.tld:port/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -127,7 +129,7 @@ void test_network_urlparse__port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__empty_port(void)
+void test_network_urlparse__hostname_empty_port(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://example.com:/resource"));
cl_assert_equal_s(conndata.scheme, "http");
@@ -139,7 +141,7 @@ void test_network_urlparse__empty_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__user_port(void)
+void test_network_urlparse__hostname_user_port(void)
{
/* user@hostname.tld:port/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -153,7 +155,7 @@ void test_network_urlparse__user_port(void)
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__user_pass_port(void)
+void test_network_urlparse__hostname_user_pass_port(void)
{
/* user:pass@hostname.tld:port/resource */
cl_git_pass(git_net_url_parse(&conndata,
@@ -166,3 +168,390 @@ void test_network_urlparse__user_pass_port(void)
cl_assert_equal_s(conndata.password, "pass");
cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
+
+/* IPv4 addresses */
+
+void test_network_urlparse__ipv4_trivial(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/resource"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv4_root(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv4_implied_root(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "42");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv4_encoded_password(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass%2fis%40bad@192.168.1.1:1234/"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "1234");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass/is@bad");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__ipv4_user(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user@192.168.1.1/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv4_user_pass(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass@192.168.1.1/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv4_port(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://192.168.1.1:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv4_user_port(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user@192.168.1.1:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__ipv4_user_pass_port(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass@192.168.1.1:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "192.168.1.1");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+/* IPv6 addresses */
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv6_root(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "42");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv6_encoded_password(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001]:1234/"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "1234");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass/is@bad");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__ipv6_user(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user@[fe80::dcad:beff:fe00:0001]/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv6_user_pass(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass@[fe80::dcad:beff:fe00:0001]/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv6_port(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://[fe80::dcad:beff:fe00:0001]:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__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");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_urlparse__ipv6_user_port(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user@[fe80::dcad:beff:fe00:0001]:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__ipv6_user_pass_port(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass@[fe80::dcad:beff:fe00:0001]:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_urlparse__ipv6_invalid_addresses(void)
+{
+ /* Opening bracket missing */
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001]/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001]/"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001]"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001]:42"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001]:"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001]:1234/"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user@fe80::dcad:beff:fe00:0001]/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass@fe80::dcad:beff:fe00:0001]/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://fe80::dcad:beff:fe00:0001]:9191/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001]:/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user@fe80::dcad:beff:fe00:0001]:9191/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass@fe80::dcad:beff:fe00:0001]:9191/resource"));
+
+ /* Closing bracket missing */
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://[fe80::dcad:beff:fe00:0001/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://[fe80::dcad:beff:fe00:0001/"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://[fe80::dcad:beff:fe00:0001"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://[fe80::dcad:beff:fe00:0001:42"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://[fe80::dcad:beff:fe00:0001:"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001:1234/"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user@[fe80::dcad:beff:fe00:0001/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass@[fe80::dcad:beff:fe00:0001/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://[fe80::dcad:beff:fe00:0001:9191/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://[fe80::dcad:beff:fe00:0001:/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user@[fe80::dcad:beff:fe00:0001:9191/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass@[fe80::dcad:beff:fe00:0001:9191/resource"));
+ /* Both brackets missing */
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001/"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001:42"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001:"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001:1234/"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user@fe80::dcad:beff:fe00:0001/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass@fe80::dcad:beff:fe00:0001/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://fe80::dcad:beff:fe00:0001:9191/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "http://fe80::dcad:beff:fe00:0001:/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user@fe80::dcad:beff:fe00:0001:9191/resource"));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+ "https://user:pass@fe80::dcad:beff:fe00:0001:9191/resource"));
+
+ /* Invalid chracter inside address */
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, "http://[fe8o::dcad:beff:fe00:0001]/resource"));
+}