From 8655991572247e764d0c00e1b31dd6b7cda56f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Thu, 22 Aug 2024 22:41:51 +0300 Subject: [PATCH] Fix IPv6 handling when converting file URL to UNC path The IPv6 address is converted to the UNC-supported IPv6 format: colons are replaced by hyphens and `.ipv6-literal.net` is appended. This is necessary because colons are not valid in UNC path components. More information: * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc * https://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_UNC_path_names --- include/upa/url.h | 12 ++++++++++-- test/test-url.cpp | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/upa/url.h b/include/upa/url.h index 6a08ddf..5a51097 100644 --- a/include/upa/url.h +++ b/include/upa/url.h @@ -31,7 +31,7 @@ #include #include #include // uint8_t -#include // std::next +#include #include #include #include @@ -3264,7 +3264,15 @@ inline std::string path_from_file_url(const url& file_url, file_path_format form throw url_error(validation_errc::file_url_unsupported_host, "UNC path cannot have \".\" hostname"); // UNC path path.append("\\\\"); - path.append(hostname); + if (file_url.host_type() == HostType::IPv6) { + // Form an IPV6 address host-name by substituting hyphens for the colons and appending ".ipv6-literal.net" + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc + std::replace_copy(std::next(hostname.begin()), std::prev(hostname.end()), + std::back_inserter(path), ':', '-'); + path.append(".ipv6-literal.net"); + } else { + path.append(hostname); + } } // percent decode pathname and normalize slashes diff --git a/test/test-url.cpp b/test/test-url.cpp index 35a1249..5ed33e5 100644 --- a/test/test-url.cpp +++ b/test/test-url.cpp @@ -761,6 +761,9 @@ TEST_CASE("path_from_file_url") { CHECK(path_from_file_url("file://host/path", upa::file_path_format::windows) == "\\\\host\\path"); CHECK(path_from_file_url("file:////host/path", upa::file_path_format::windows) == "\\\\host\\path"); CHECK(path_from_file_url("file://///host/path", upa::file_path_format::windows) == "\\\\host\\path"); + // UNC: IPv4 and IPv6 hostnames + CHECK(path_from_file_url("file://127.0.0.1/path", upa::file_path_format::windows) == "\\\\127.0.0.1\\path"); + CHECK(path_from_file_url("file://[::1]/path", upa::file_path_format::windows) == "\\\\--1.ipv6-literal.net\\path"); // Invalid UNC CHECK_THROWS_AS(path_from_file_url("file://host", upa::file_path_format::windows), upa::url_error); CHECK_THROWS_AS(path_from_file_url("file://host/", upa::file_path_format::windows), upa::url_error);