From dafde0e2d5382571bfb91339e3f9e9a5530738b0 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 3 Oct 2024 09:34:01 +0900
Subject: [PATCH] libpq: Count for leading and trailing whitespaces in URIs

---
 src/interfaces/libpq/fe-connect.c | 42 ++++++++++++++++++++++++++-----
 src/interfaces/libpq/t/001_uri.pl | 11 ++++++++
 2 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 64787bea51..2d09ea5afd 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6763,9 +6763,9 @@ conninfo_uri_parse_params(char *params,
 static char *
 conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
 {
-	char	   *buf;
-	char	   *p;
-	const char *q = str;
+	char	   *buf;	/* result */
+	char	   *p;		/* output location */
+	const char *q = str;	/* input location */
 
 	buf = malloc(strlen(str) + 1);
 	if (buf == NULL)
@@ -6775,13 +6775,23 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
 	}
 	p = buf;
 
+	/* skip leading whitespaces */
+	for (const char *s = q; *s == ' '; s++)
+	{
+		q++;
+		continue;
+	}
+
 	for (;;)
 	{
 		if (*q != '%')
 		{
-			/* copy and check for NUL terminator */
-			if (!(*(p++) = *(q++)))
-				break;
+			/* if found a whitespace or NUL, the string ends */
+			if (*q == ' ' || *q == '\0')
+				goto end;
+
+			/* copy character */
+			*(p++) = *(q++);
 		}
 		else
 		{
@@ -6817,6 +6827,26 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
 		}
 	}
 
+end:
+
+	/* skip trailing whitespaces */
+	for (const char *s = q; *s == ' '; s++)
+	{
+		q++;
+		continue;
+	}
+
+	/* Not at the end of the string yet?  Fail. */
+	if (*q != '\0')
+	{
+		libpq_append_error(errorMessage, "trailing data found: \"%s\"", str);
+		free(buf);
+		return NULL;
+	}
+
+	/* Copy NUL terminator */
+	*p = '\0';
+
 	return buf;
 }
 
diff --git a/src/interfaces/libpq/t/001_uri.pl b/src/interfaces/libpq/t/001_uri.pl
index 49ea5377e0..a872e973e7 100644
--- a/src/interfaces/libpq/t/001_uri.pl
+++ b/src/interfaces/libpq/t/001_uri.pl
@@ -86,6 +86,17 @@ my @tests = (
 		q{user='uri-user' host='host' (inet)},
 		q{},
 	],
+	[
+		# Leading and trailing spaces, works
+		q{postgresql://host? user  = uri-user & port  = 12345 },
+		q{user='uri-user' host='host' port='12345' (inet)},
+		q{},
+	],
+	[
+		q{postgresql://host?  host  =  uri-user & port = 12345 12 },
+		q{},
+		q{libpq_uri_regress: trailing data found: " 12345 12 "},
+	],
 	[ q{postgresql://host?}, q{host='host' (inet)}, q{}, ],
 	[
 		q{postgresql://[::1]:12345/db},
-- 
2.45.2

