git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 02/14] url: decode buffers that are not NUL-terminated

From
Jeff King <peff@peff.net>
Date
Jul 18, 2011, 07:48 UTC
Message-ID
<20110718074851.GB12341@sigill.intra.peff.net>
In-Reply-To
<20110718074642.GA11678@sigill.intra.peff.net>

The url_decode function needs only minor tweaks to handle arbitrary buffers. Let's do those tweaks, which cleans up an unreadable mess of temporary strings in http.c.

Signed-off-by: Jeff King <peff@peff.net>
---
 http.c |   27 ++++-----------------------
 url.c  |   26 ++++++++++++++++++--------
 url.h  |    1 +
 3 files changed, 23 insertions(+), 31 deletions(-)
diff --git a/http.c b/http.c
index a1ea3db..c93716c 100644
--- a/http.c
+++ b/http.c
@@ -307,8 +307,7 @@ static CURL *get_curl_handle(void)
 
 static void http_auth_init(const char *url)
 {
-	char *at, *colon, *cp, *slash, *decoded;
-	int len;
+	char *at, *colon, *cp, *slash;
 
 	cp = strstr(url, "://");
 	if (!cp)
@@ -328,29 +327,11 @@ static void http_auth_init(const char *url)
 		return; /* No credentials */
 	if (!colon || at <= colon) {
 		/* Only username */
-		len = at - cp;
-		user_name = xmalloc(len + 1);
-		memcpy(user_name, cp, len);
-		user_name[len] = '\0';
-		decoded = url_decode(user_name);
-		free(user_name);
-		user_name = decoded;
+		user_name = url_decode_mem(cp, at - cp);
 		user_pass = NULL;
 	} else {
-		len = colon - cp;
-		user_name = xmalloc(len + 1);
-		memcpy(user_name, cp, len);
-		user_name[len] = '\0';
-		decoded = url_decode(user_name);
-		free(user_name);
-		user_name = decoded;
-		len = at - (colon + 1);
-		user_pass = xmalloc(len + 1);
-		memcpy(user_pass, colon + 1, len);
-		user_pass[len] = '\0';
-		decoded = url_decode(user_pass);
-		free(user_pass);
-		user_pass = decoded;
+		user_name = url_decode_mem(cp, colon - cp);
+		user_pass = url_decode_mem(colon + 1, at - (colon + 1));
 	}
 }
 
diff --git a/url.c b/url.c
index 3e06fd3..389d9da 100644
--- a/url.c
+++ b/url.c
@@ -68,18 +68,20 @@ static int url_decode_char(const char *q)
 	return val;
 }
 
-static char *url_decode_internal(const char **query, const char *stop_at,
-				 struct strbuf *out, int decode_plus)
+static char *url_decode_internal(const char **query, int len,
+				 const char *stop_at, struct strbuf *out,
+				 int decode_plus)
 {
 	const char *q = *query;
 
-	do {
+	while (len) {
 		unsigned char c = *q;
 
 		if (!c)
 			break;
 		if (stop_at && strchr(stop_at, c)) {
 			q++;
+			len--;
 			break;
 		}
 
@@ -88,6 +90,7 @@ static char *url_decode_internal(const char **query, const char *stop_at,
 			if (0 <= val) {
 				strbuf_addch(out, val);
 				q += 3;
+				len -= 3;
 				continue;
 			}
 		}
@@ -97,34 +100,41 @@ static char *url_decode_internal(const char **query, const char *stop_at,
 		else
 			strbuf_addch(out, c);
 		q++;
-	} while (1);
+		len--;
+	}
 	*query = q;
 	return strbuf_detach(out, NULL);
 }
 
 char *url_decode(const char *url)
 {
+	return url_decode_mem(url, strlen(url));
+}
+
+char *url_decode_mem(const char *url, int len)
+{
 	struct strbuf out = STRBUF_INIT;
-	const char *colon = strchr(url, ':');
+	const char *colon = memchr(url, ':', len);
 
 	/* Skip protocol part if present */
 	if (colon && url < colon) {
 		strbuf_add(&out, url, colon - url);
+		len -= colon - url;
 		url = colon;
 	}
-	return url_decode_internal(&url, NULL, &out, 0);
+	return url_decode_internal(&url, len, NULL, &out, 0);
 }
 
 char *url_decode_parameter_name(const char **query)
 {
 	struct strbuf out = STRBUF_INIT;
-	return url_decode_internal(query, "&=", &out, 1);
+	return url_decode_internal(query, -1, "&=", &out, 1);
 }
 
 char *url_decode_parameter_value(const char **query)
 {
 	struct strbuf out = STRBUF_INIT;
-	return url_decode_internal(query, "&", &out, 1);
+	return url_decode_internal(query, -1, "&", &out, 1);
 }
 
 void end_url_with_slash(struct strbuf *buf, const char *url)
diff --git a/url.h b/url.h
index 7100e32..abdaf6f 100644
--- a/url.h
+++ b/url.h
@@ -4,6 +4,7 @@
 extern int is_url(const char *url);
 extern int is_urlschemechar(int first_flag, int ch);
 extern char *url_decode(const char *url);
+extern char *url_decode_mem(const char *url, int len);
 extern char *url_decode_parameter_name(const char **query);
 extern char *url_decode_parameter_value(const char **query);
 
-- 
1.7.6.rc1.12.g65e2
Previous: Jeff KingNext: Junio C Hamano
Message 3 of 33 in “less annoying http authentication”
  1. 0/14 less annoying http authenticationJeff King, Jul 18, 2011
  2. 01/14 parse-options: add OPT_STRING_LIST helperJeff King, Jul 18, 2011
  3. 02/14 url: decode buffers that are not NUL-terminatedJeff King, Jul 18, 2011
  4. Junio C HamanoJul 20, 2011
  5. 03/14 improve httpd auth testsJeff King, Jul 18, 2011
  6. 04/14 remote-curl: don't retry auth failures with dumb protocolJeff King, Jul 18, 2011
  7. 05/14 http: retry authentication failures for all http requestsJeff King, Jul 18, 2011
  8. 06/14 introduce credentials APIJeff King, Jul 18, 2011
  9. Junio C HamanoJul 20, 2011
  10. Jeff KingJul 22, 2011
  11. Junio C HamanoJul 22, 2011
  12. Jeff KingJul 22, 2011
  13. Junio C HamanoJul 21, 2011
  14. Jeff KingJul 22, 2011
  15. 07/14 http: use credential API to get passwordsJeff King, Jul 18, 2011
  16. 08/14 look for credentials in config before promptingJeff King, Jul 18, 2011
  17. 09/14 allow the user to configure credential helpersJeff King, Jul 18, 2011
  18. 10/14 http: use hostname in credential descriptionJeff King, Jul 18, 2011
  19. Junio C HamanoJul 20, 2011
  20. Jeff KingJul 22, 2011
  21. Junio C HamanoJul 22, 2011
  22. Jeff KingJul 22, 2011
  23. Ted ZlatanovAug 8, 2011
  24. Junio C HamanoAug 8, 2011
  25. Ted ZlatanovAug 19, 2011
  26. Jeff KingAug 25, 2011
  27. Ted ZlatanovAug 26, 2011
  28. 11/14 docs: end-user documentation for the credential subsystemJeff King, Jul 18, 2011
  29. Junio C HamanoJul 20, 2011
  30. 12/14 credentials: add "cache" helperJeff King, Jul 18, 2011
  31. 13/14 credentials: add "store" helperJeff King, Jul 18, 2011
  32. 14/14 credentials: add "getpass" helperJeff King, Jul 18, 2011
  33. Jeff KingJul 18, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.