url: support IPv6 literals (RFC 2732) (#292)
This commit is contained in:
parent
8bed1cc743
commit
874a1d8c33
@ -54,6 +54,12 @@ public:
|
|||||||
return c >= '0' && c <= '9';
|
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) {
|
static bool isAlpha(const char_t c) {
|
||||||
|
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
|
@ -126,7 +126,7 @@ const string url::build() const {
|
|||||||
oss << "@";
|
oss << "@";
|
||||||
}
|
}
|
||||||
|
|
||||||
oss << urlUtils::encode(m_host);
|
oss << urlUtils::encodeHost(m_host);
|
||||||
|
|
||||||
if (m_port != UNSPECIFIED_PORT) {
|
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) {
|
void url::parse(const string& str) {
|
||||||
|
|
||||||
// Protocol
|
// Protocol
|
||||||
@ -222,20 +269,9 @@ void url::parse(const string& str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Host/port
|
// Host/port
|
||||||
const size_t colonPos = hostPart.find(':');
|
|
||||||
|
|
||||||
string host;
|
string host;
|
||||||
string port;
|
string port;
|
||||||
|
extractHost(hostPart, host, 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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Path
|
// Path
|
||||||
string path = utility::stringUtils::trim(string(str.begin() + slashPos, str.end()));
|
string path = utility::stringUtils::trim(string(str.begin() + slashPos, str.end()));
|
||||||
|
@ -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) {
|
const string urlUtils::decode(const string& s) {
|
||||||
|
|
||||||
string result;
|
string result;
|
||||||
|
@ -44,6 +44,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
static const string encode(const string& s);
|
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()).
|
/** Decode an hex-encoded URL (see encode()).
|
||||||
*/
|
*/
|
||||||
static const string decode(const string& s);
|
static const string decode(const string& s);
|
||||||
|
@ -35,6 +35,7 @@ VMIME_TEST_SUITE_BEGIN(urlTest)
|
|||||||
VMIME_TEST(testParse3)
|
VMIME_TEST(testParse3)
|
||||||
VMIME_TEST(testParse4)
|
VMIME_TEST(testParse4)
|
||||||
VMIME_TEST(testParse5)
|
VMIME_TEST(testParse5)
|
||||||
|
VMIME_TEST(testParseIPv6)
|
||||||
VMIME_TEST(testGenerate)
|
VMIME_TEST(testGenerate)
|
||||||
VMIME_TEST(testUtilsEncode)
|
VMIME_TEST(testUtilsEncode)
|
||||||
VMIME_TEST(testUtilsDecode)
|
VMIME_TEST(testUtilsDecode)
|
||||||
@ -201,6 +202,18 @@ VMIME_TEST_SUITE_BEGIN(urlTest)
|
|||||||
VASSERT_EQ("4", "myserver.com", u1.getHost());
|
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() {
|
void testGenerate() {
|
||||||
|
|
||||||
vmime::utility::url u1("proto", "host", 12345, "path", "user", "password");
|
vmime::utility::url u1("proto", "host", 12345, "path", "user", "password");
|
||||||
@ -235,6 +248,13 @@ VMIME_TEST_SUITE_BEGIN(urlTest)
|
|||||||
"proto://host/?%26=%3D",
|
"proto://host/?%26=%3D",
|
||||||
static_cast <vmime::string>(u3)
|
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() {
|
void testUtilsEncode() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user