Commit 7e0359084ef0faba8f458f9cccad2dc8f5baf800

Ben Straub 2013-11-01T15:29:25

Streamline url-parsing logic.

diff --git a/src/netops.c b/src/netops.c
index 7e13f12..0bf3a8f 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -668,47 +668,47 @@ int gitno_extract_url_parts(
 		const char *url,
 		const char *default_port)
 {
-	char *colon, *slash, *at, *end;
-	const char *start;
+	char *colon, *slash, *at;
 
 	/*
 	 * ==> [user[:pass]@]hostname.tld[:port]/resource
 	 */
 
-	colon = strchr(url, ':');
-	slash = strchr(url, '/');
+	/* Check for user and maybe password */
 	at = strchr(url, '@');
+	if (at) {
+		colon = strchr(url, ':');
+		if (colon && colon < at) {
+			/* user:pass */
+			*username = git__substrdup(url, colon-url);
+			*password = git__substrdup(colon+1, at-colon-1);
+			GITERR_CHECK_ALLOC(*password);
+		} else {
+			*username = git__substrdup(url, at-url);
+		}
+		GITERR_CHECK_ALLOC(*username);
+		url = at + 1;
+	}
 
+	/* Validate URL format. Colons shouldn't be in the path part. */
+	slash = strchr(url, '/');
+	colon = strchr(url, ':');
 	if (!slash ||
 	    (colon && (slash < colon))) {
 		giterr_set(GITERR_NET, "Malformed URL");
 		return GIT_EINVALIDSPEC;
 	}
 
-	start = url;
-	if (at && at < slash) {
-		start = at+1;
-		*username = git__substrdup(url, at - url);
-	}
-
-	if (colon && colon < at) {
-		git__free(*username);
-		*username = git__substrdup(url, colon-url);
-		*password = git__substrdup(colon+1, at-colon-1);
-		colon = strchr(at, ':');
-	}
-
-	if (colon == NULL) {
-		*port = git__strdup(default_port);
+	/* Check for hostname and maybe port */
+	if (colon) {
+		*host = git__substrdup(url, colon-url);
+		*port = git__substrdup(colon+1, slash-colon-1);
 	} else {
-		*port = git__substrdup(colon + 1, slash - colon - 1);
+		*host = git__substrdup(url, slash-url);
+		*port = git__strdup(default_port);
 	}
-	GITERR_CHECK_ALLOC(*port);
-
-	end = colon == NULL ? slash : colon;
-
-	*host = git__substrdup(start, end - start);
 	GITERR_CHECK_ALLOC(*host);
+	GITERR_CHECK_ALLOC(*port);
 
 	return 0;
 }
diff --git a/tests-clar/network/urlparse.c b/tests-clar/network/urlparse.c
index 15e841b..9fc304a 100644
--- a/tests-clar/network/urlparse.c
+++ b/tests-clar/network/urlparse.c
@@ -38,6 +38,16 @@ void test_network_urlparse__bad_url(void)
 			GIT_EINVALIDSPEC);
 }
 
+void test_network_urlparse__weird_url(void)
+{
+	cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass,
+				"arrbee:my/bad:password@github.com:1111/strange/words.git", "1"));
+	cl_assert_equal_s(host, "github.com");
+	cl_assert_equal_s(port, "1111");
+	cl_assert_equal_s(user, "arrbee");
+	cl_assert_equal_s(pass, "my/bad:password");
+}
+
 void test_network_urlparse__user(void)
 {
 	cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass,