summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-06-07 19:40:15 (GMT)
committerKevin Smith <kevin.smith@isode.com>2016-06-14 20:04:42 (GMT)
commit0d5dcec01a396ab64c559a5b0cd04eb38f2f1954 (patch)
tree64bc61c8f51313787717afacfd5a8e4cc777b778 /Swiften
parent1dbcf543910b85b53a95461ed4770264e0ddbc4c (diff)
downloadswift-0d5dcec01a396ab64c559a5b0cd04eb38f2f1954.zip
swift-0d5dcec01a396ab64c559a5b0cd04eb38f2f1954.tar.bz2
Add support for URLs with IPv6 addresses in Swift::URL
Test-Information: Added unit tests and test cases from RFC 2732. All tests pass on OS X 10.11.5. Change-Id: Ic76e57985109912871c05d12253f73d3653bd7a3
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Base/URL.cpp45
-rw-r--r--Swiften/Base/UnitTest/URLTest.cpp123
2 files changed, 159 insertions, 9 deletions
diff --git a/Swiften/Base/URL.cpp b/Swiften/Base/URL.cpp
index a9a1140..4a47a11 100644
--- a/Swiften/Base/URL.cpp
+++ b/Swiften/Base/URL.cpp
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Base/URL.h>
+#include <algorithm>
#include <iostream>
namespace Swift {
@@ -62,18 +63,39 @@ URL URL::fromString(const std::string& urlString) {
std::string host;
boost::optional<int> port;
- colonIndex = hostAndPort.find(':');
- if (colonIndex != std::string::npos) {
- host = unescape(hostAndPort.substr(0, colonIndex));
- try {
- port = boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1));
+ if (hostAndPort[0] == '[') {
+ // handle IPv6 address literals
+ size_t addressEndIndex = hostAndPort.find(']');
+ if (addressEndIndex != std::string::npos) {
+ host = hostAndPort.substr(1, addressEndIndex - 1);
+ colonIndex = hostAndPort.find(':', addressEndIndex);
+ if (colonIndex != std::string::npos) {
+ try {
+ port = boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1));
+ }
+ catch (const boost::bad_lexical_cast&) {
+ return URL();
+ }
+ }
}
- catch (const boost::bad_lexical_cast&) {
+ else {
return URL();
}
}
else {
- host = unescape(hostAndPort);
+ colonIndex = hostAndPort.find(':');
+ if (colonIndex != std::string::npos) {
+ host = unescape(hostAndPort.substr(0, colonIndex));
+ try {
+ port = boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1));
+ }
+ catch (const boost::bad_lexical_cast&) {
+ return URL();
+ }
+ }
+ else {
+ host = unescape(hostAndPort);
+ }
}
if (port) {
@@ -102,7 +124,12 @@ std::string URL::toString() const {
}
result += "@";
}
- result += host;
+ if (host.find(':') != std::string::npos) {
+ result += "[" + host + "]";
+ }
+ else {
+ result += host;
+ }
if (port) {
result += ":";
result += boost::lexical_cast<std::string>(*port);
diff --git a/Swiften/Base/UnitTest/URLTest.cpp b/Swiften/Base/UnitTest/URLTest.cpp
index 2d2ceba..c38398a 100644
--- a/Swiften/Base/UnitTest/URLTest.cpp
+++ b/Swiften/Base/UnitTest/URLTest.cpp
@@ -24,8 +24,13 @@ class URLTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testFromString_WithUserInfo);
CPPUNIT_TEST(testFromString_NonASCIIHost);
CPPUNIT_TEST(testFromString_NonASCIIPath);
+ CPPUNIT_TEST(testFromString_IPv4Address);
+ CPPUNIT_TEST(testFromString_IPv4AddressWithPort);
+ CPPUNIT_TEST(testFromString_IPv6Address);
+ CPPUNIT_TEST(testFromString_IPv6AddressWithPort);
CPPUNIT_TEST(testToString);
CPPUNIT_TEST(testToString_WithPort);
+ CPPUNIT_TEST(test_FromString_ToString_IPv6RFC2732);
CPPUNIT_TEST_SUITE_END();
public:
@@ -103,6 +108,124 @@ class URLTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(std::string("/baz/tron\xc3\xa7on/bam"), url.getPath());
}
+ void testFromString_IPv4Address() {
+ URL url = URL::fromString("http://127.0.0.1/foobar");
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(std::string("/foobar"), url.getPath());
+ }
+
+ void testFromString_IPv4AddressWithPort() {
+ URL url = URL::fromString("http://127.0.0.1:12345/foobar");
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(12345, url.getPort().get_value_or(0));
+ CPPUNIT_ASSERT_EQUAL(std::string("/foobar"), url.getPath());
+ }
+
+ void testFromString_IPv6Address() {
+ URL url = URL::fromString("http://[fdf8:f53b:82e4::53]/foobar");
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("fdf8:f53b:82e4::53"), url.getHost());
+ }
+
+ void testFromString_IPv6AddressWithPort() {
+ URL url = URL::fromString("http://[fdf8:f53b:82e4::53]:12435/foobar");
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("fdf8:f53b:82e4::53"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(12435, url.getPort().get_value_or(0));
+ }
+
+ void test_FromString_ToString_IPv6RFC2732() {
+ {
+ const char* testVector = "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(80, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string("/index.html"), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+
+ {
+ const char* testVector = "http://[1080:0:0:0:8:800:200C:417A]/index.html";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("1080:0:0:0:8:800:200C:417A"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string("/index.html"), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+
+ {
+ const char* testVector = "http://[3ffe:2a00:100:7031::1]";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("3ffe:2a00:100:7031::1"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string(""), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+
+ {
+ const char* testVector = "http://[1080::8:800:200C:417A]/foo";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("1080::8:800:200C:417A"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string("/foo"), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+
+ {
+ const char* testVector = "http://[::192.9.5.5]/ipng";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("::192.9.5.5"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string("/ipng"), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+
+ {
+ const char* testVector = "http://[::FFFF:129.144.52.38]:80/index.html";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("::FFFF:129.144.52.38"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(80, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string("/index.html"), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+
+ {
+ const char* testVector = "http://[2010:836B:4179::836B:4179]";
+ URL url = URL::fromString(testVector);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme());
+ CPPUNIT_ASSERT_EQUAL(std::string("2010:836B:4179::836B:4179"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2));
+ CPPUNIT_ASSERT_EQUAL(std::string(), url.getPath());
+
+ CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString());
+ }
+ }
+
void testToString() {
CPPUNIT_ASSERT_EQUAL(std::string("http://foo.bar/baz/bam"), URL("http", "foo.bar", "/baz/bam").toString());
}