diff options
author | Jan Engelhardt <[email protected]> | 2024-01-30 11:38:41 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2024-01-30 11:38:41 +0000 |
commit | 874a1d8c33ef80402be95a1ebee01902e14f12e4 (patch) | |
tree | f9ab1cbf69df0010c2d273357f65f50564d5b1d3 | |
parent | Fixed confusing source/bin dirs in makefile. (#291) (diff) | |
download | vmime-874a1d8c33ef80402be95a1ebee01902e14f12e4.tar.gz vmime-874a1d8c33ef80402be95a1ebee01902e14f12e4.zip |
url: support IPv6 literals (RFC 2732) (#292)
-rw-r--r-- | src/vmime/parserHelpers.hpp | 6 | ||||
-rw-r--r-- | src/vmime/utility/url.cpp | 62 | ||||
-rw-r--r-- | src/vmime/utility/urlUtils.cpp | 16 | ||||
-rw-r--r-- | src/vmime/utility/urlUtils.hpp | 4 | ||||
-rw-r--r-- | tests/utility/urlTest.cpp | 20 |
5 files changed, 95 insertions, 13 deletions
diff --git a/src/vmime/parserHelpers.hpp b/src/vmime/parserHelpers.hpp index cba43c6c..f150a355 100644 --- a/src/vmime/parserHelpers.hpp +++ b/src/vmime/parserHelpers.hpp @@ -54,6 +54,12 @@ public: return c >= '0' && c <= '9'; } + static bool isXDigit(const char_t c) { + + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); + } + static bool isAlpha(const char_t c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); diff --git a/src/vmime/utility/url.cpp b/src/vmime/utility/url.cpp index 59cb1f51..334e78fc 100644 --- a/src/vmime/utility/url.cpp +++ b/src/vmime/utility/url.cpp @@ -126,7 +126,7 @@ const string url::build() const { oss << "@"; } - oss << urlUtils::encode(m_host); + oss << urlUtils::encodeHost(m_host); if (m_port != UNSPECIFIED_PORT) { @@ -166,6 +166,53 @@ const string url::build() const { } +static bool extractHostIPv6(string& hostPart, string& host, string& port) { + + if (hostPart[0] != '[') { + return false; + } + + const auto len = hostPart.find(']'); + + if (len == string::npos) { + return false; + } + + host.assign(&hostPart[1], len - 1); + + if (hostPart[len] == '\0') { + return true; + } + if (hostPart[len + 1] != ':') { + return false; + } + + port = hostPart.substr(len + 2); + + return true; +} + + +static void extractHost(string& hostPart, string& host, string& port) { + + if (extractHostIPv6(hostPart, host, port)) { + return; + } + + const size_t colonPos = hostPart.find(':'); + + if (colonPos == string::npos) { + + host = utility::stringUtils::trim(hostPart); + + } else { + + host = utility::stringUtils::trim(string(hostPart.begin(), hostPart.begin() + colonPos)); + port = utility::stringUtils::trim(string(hostPart.begin() + colonPos + 1, hostPart.end())); + } +} + + void url::parse(const string& str) { // Protocol @@ -222,20 +269,9 @@ void url::parse(const string& str) { } // Host/port - const size_t colonPos = hostPart.find(':'); - string host; string port; - - if (colonPos == string::npos) { - - host = utility::stringUtils::trim(hostPart); - - } else { - - host = utility::stringUtils::trim(string(hostPart.begin(), hostPart.begin() + colonPos)); - port = utility::stringUtils::trim(string(hostPart.begin() + colonPos + 1, hostPart.end())); - } + extractHost(hostPart, host, port); // Path string path = utility::stringUtils::trim(string(str.begin() + slashPos, str.end())); diff --git a/src/vmime/utility/urlUtils.cpp b/src/vmime/utility/urlUtils.cpp index cf51a506..ca0f9c6b 100644 --- a/src/vmime/utility/urlUtils.cpp +++ b/src/vmime/utility/urlUtils.cpp @@ -66,6 +66,22 @@ const string urlUtils::encode(const string& s) { } +const string urlUtils::encodeHost(const string& s) { + + if (s.size() == 0) { + return encode(s); + } + + for (auto it = s.begin() + 1 ; it != s.end() - 1 ; ++it) { + if (!parserHelpers::isXDigit(*it) && *it != ':') { + return encode(s); + } + } + + return "[" + s + "]"; +} + + const string urlUtils::decode(const string& s) { string result; diff --git a/src/vmime/utility/urlUtils.hpp b/src/vmime/utility/urlUtils.hpp index 54ffa2ac..63689816 100644 --- a/src/vmime/utility/urlUtils.hpp +++ b/src/vmime/utility/urlUtils.hpp @@ -44,6 +44,10 @@ public: */ static const string encode(const string& s); + /** Encode the host portion of a URL string. + */ + static const string encodeHost(const string& s); + /** Decode an hex-encoded URL (see encode()). */ static const string decode(const string& s); diff --git a/tests/utility/urlTest.cpp b/tests/utility/urlTest.cpp index d26cfb81..c792c772 100644 --- a/tests/utility/urlTest.cpp +++ b/tests/utility/urlTest.cpp @@ -35,6 +35,7 @@ VMIME_TEST_SUITE_BEGIN(urlTest) VMIME_TEST(testParse3) VMIME_TEST(testParse4) VMIME_TEST(testParse5) + VMIME_TEST(testParseIPv6) VMIME_TEST(testGenerate) VMIME_TEST(testUtilsEncode) VMIME_TEST(testUtilsDecode) @@ -201,6 +202,18 @@ VMIME_TEST_SUITE_BEGIN(urlTest) VASSERT_EQ("4", "myserver.com", u1.getHost()); } + void testParseIPv6() { + + vmime::utility::url u1("", ""); + + VASSERT_EQ("1", true, parseHelper(u1, "http://a:b@[::1]:80/p")); + VASSERT_EQ("2", "a", u1.getUsername()); + VASSERT_EQ("3", "b", u1.getPassword()); + VASSERT_EQ("4", "::1", u1.getHost()); + VASSERT_EQ("5", 80, u1.getPort()); + VASSERT_EQ("6", "/p", u1.getPath()); + } + void testGenerate() { vmime::utility::url u1("proto", "host", 12345, "path", "user", "password"); @@ -235,6 +248,13 @@ VMIME_TEST_SUITE_BEGIN(urlTest) "proto://host/?%26=%3D", static_cast <vmime::string>(u3) ); + + vmime::utility::url u5("http", "::1", 80, "p"); + VASSERT_EQ( + "4", + "http://[::1]:80/p", + static_cast <vmime::string>(u5) + ); } void testUtilsEncode() { |