[1/7] lib/url: Parse IPv6 URLs

Message ID 20180509053705.3143-2-sam@mendozajonas.com
State Changes Requested
Headers show
Series
  • IPv6 Support
Related show

Commit Message

Samuel Mendoza-Jonas May 9, 2018, 5:36 a.m.
Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 lib/url/url.c                      | 32 +++++++++++++++++++++++++-----
 test/urls/Makefile.am              |  3 +++
 test/urls/data/ipv6-full.test      |  7 +++++++
 test/urls/data/ipv6-multidirs.test |  7 +++++++
 test/urls/data/ipv6-noport.test    |  7 +++++++
 5 files changed, 51 insertions(+), 5 deletions(-)
 create mode 100644 test/urls/data/ipv6-full.test
 create mode 100644 test/urls/data/ipv6-multidirs.test
 create mode 100644 test/urls/data/ipv6-noport.test

Patch

diff --git a/lib/url/url.c b/lib/url/url.c
index 6eeced3..830151e 100644
--- a/lib/url/url.c
+++ b/lib/url/url.c
@@ -20,6 +20,7 @@ 
 #include "config.h"
 #endif
 
+#include <arpa/inet.h>
 #include <assert.h>
 #include <string.h>
 
@@ -197,19 +198,35 @@  struct pb_url *pb_url_parse(void *ctx, const char *url_str)
 			goto fail;
 		}
 
-		col = strchr(p, ':');
+		col = strrchr(p, ':');
+		if (col <= p)
+			col = NULL;
+		if (col && strchr(col , ']')) {
+			/*
+			 * This is likely an IPv6 address with no port.
+			 * See https://www.ietf.org/rfc/rfc2732.txt
+			 */
+			col = NULL;
+		}
 
 		if (col) {
 			len = path - col - 1;
 			url->port = len ? talloc_strndup(url, col + 1, len)
 				: NULL;
 			len = col - p;
-			url->host = len ? talloc_strndup(url, p, len) : NULL;
 		} else {
 			url->port = NULL;
-			url->host = talloc_strndup(url, p, path - p);
+			len = path - p;
 		}
 
+		if (p[0] == '[' && p[len - 1] == ']')
+			/* IPv6 */
+			url->host = talloc_strndup(url, p + 1, len - 2);
+		else
+			/* IPv4 */
+			url->host = talloc_strndup(url, p, len);
+
+
 		/* remove multiple leading slashes */
 		for (; *path && *(path+1) == '/'; path++)
 			;
@@ -234,10 +251,15 @@  bool is_url(const char *str)
 char *pb_url_to_string(struct pb_url *url)
 {
 	const struct pb_scheme_info *scheme = pb_url_scheme_info(url->scheme);
+	uint8_t addr[INET6_ADDRSTRLEN];
 	assert(scheme);
 
-	return talloc_asprintf(url, "%s://%s%s", scheme->str,
-			scheme->has_host ? url->host : "", url->path);
+	if (scheme->has_host && inet_pton(AF_INET6, url->host, addr) == 1)
+		return talloc_asprintf(url, "%s://[%s]%s", scheme->str,
+				url->host, url->path);
+	else
+		return talloc_asprintf(url, "%s://%s%s", scheme->str,
+				scheme->has_host ? url->host : "", url->path);
 }
 
 static void pb_url_update_full(struct pb_url *url)
diff --git a/test/urls/Makefile.am b/test/urls/Makefile.am
index ad670b8..aab0f2b 100644
--- a/test/urls/Makefile.am
+++ b/test/urls/Makefile.am
@@ -20,6 +20,9 @@  test_urls_parse_url_LDADD = $(core_lib)
 url_TESTS = \
 	test/urls/data/double-slash.test \
 	test/urls/data/http-simple.test \
+	test/urls/data/ipv6-full.test \
+	test/urls/data/ipv6-multidirs.test \
+	test/urls/data/ipv6-noport.test \
 	test/urls/data/join-full.test \
 	test/urls/data/join-absolute.test \
 	test/urls/data/join-relative.test \
diff --git a/test/urls/data/ipv6-full.test b/test/urls/data/ipv6-full.test
new file mode 100644
index 0000000..b4943eb
--- /dev/null
+++ b/test/urls/data/ipv6-full.test
@@ -0,0 +1,7 @@ 
+http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
+scheme	http
+host	FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
+port	80
+path	/index.html
+dir	/
+file	index.html
diff --git a/test/urls/data/ipv6-multidirs.test b/test/urls/data/ipv6-multidirs.test
new file mode 100644
index 0000000..68b852a
--- /dev/null
+++ b/test/urls/data/ipv6-multidirs.test
@@ -0,0 +1,7 @@ 
+tftp://[fd69:d65f:b8b5:61::1]/installers/ubuntu-18.04/vmlinux
+scheme	tftp
+host	fd69:d65f:b8b5:61::1
+port	(null)
+path	/installers/ubuntu-18.04/vmlinux
+dir	/installers/ubuntu-18.04/
+file	vmlinux
diff --git a/test/urls/data/ipv6-noport.test b/test/urls/data/ipv6-noport.test
new file mode 100644
index 0000000..bd3b008
--- /dev/null
+++ b/test/urls/data/ipv6-noport.test
@@ -0,0 +1,7 @@ 
+http://[1080:0:0:0:8:800:200C:417A]/index.html
+scheme	http
+host	1080:0:0:0:8:800:200C:417A
+port	(null)
+path	/index.html
+dir	/
+file	index.html