Skip to content

Commit

Permalink
Fix IPv6 handling when converting file URL to UNC path
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rmisev committed Aug 22, 2024
1 parent cd67f44 commit 8655991
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 2 deletions.
12 changes: 10 additions & 2 deletions include/upa/url.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <cassert>
#include <cstddef>
#include <cstdint> // uint8_t
#include <iterator> // std::next
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions test/test-url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 8655991

Please sign in to comment.