diff options
Diffstat (limited to 'Swiften/Base/URL.cpp')
-rw-r--r-- | Swiften/Base/URL.cpp | 307 |
1 files changed, 167 insertions, 140 deletions
diff --git a/Swiften/Base/URL.cpp b/Swiften/Base/URL.cpp index 28eba1e..4a47a11 100644 --- a/Swiften/Base/URL.cpp +++ b/Swiften/Base/URL.cpp @@ -1,114 +1,141 @@ /* - * 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 { int URL::getPortOrDefaultPort(const URL& url) { - if (url.getPort()) { - return *url.getPort(); - } - else if (url.getScheme() == "http") { - return 80; - } - else if (url.getScheme() == "https") { - return 443; - } - else { - std::cerr << "Unknown scheme: " + url.getScheme() << std::endl; - return 80; - } + if (url.getPort()) { + return *url.getPort(); + } + else if (url.getScheme() == "http") { + return 80; + } + else if (url.getScheme() == "https") { + return 443; + } + else { + std::cerr << "Unknown scheme: " + url.getScheme() << std::endl; + return 80; + } } URL URL::fromString(const std::string& urlString) { - size_t colonIndex = urlString.find(':'); - if (colonIndex == std::string::npos) { - return URL(); - } - std::string scheme = urlString.substr(0, colonIndex); + size_t colonIndex = urlString.find(':'); + if (colonIndex == std::string::npos) { + return URL(); + } + std::string scheme = urlString.substr(0, colonIndex); - // Authority - if (urlString.size() > colonIndex + 2 && urlString[colonIndex+1] == '/' && urlString[colonIndex+2] == '/') { - size_t authorityIndex = colonIndex + 3; - size_t slashIndex = urlString.find('/', authorityIndex); - std::string authority; - std::string path; - if (slashIndex == std::string::npos) { - authority = urlString.substr(authorityIndex); - path = ""; - } - else { - authority = urlString.substr(authorityIndex, slashIndex - authorityIndex); - path = unescape(urlString.substr(slashIndex)); - } + // Authority + if (urlString.size() > colonIndex + 2 && urlString[colonIndex+1] == '/' && urlString[colonIndex+2] == '/') { + size_t authorityIndex = colonIndex + 3; + size_t slashIndex = urlString.find('/', authorityIndex); + std::string authority; + std::string path; + if (slashIndex == std::string::npos) { + authority = urlString.substr(authorityIndex); + path = ""; + } + else { + authority = urlString.substr(authorityIndex, slashIndex - authorityIndex); + path = unescape(urlString.substr(slashIndex)); + } - size_t atIndex = authority.find('@'); - std::string userInfo; - std::string hostAndPort; - if (atIndex != std::string::npos) { - userInfo = authority.substr(0, atIndex); - hostAndPort = authority.substr(atIndex + 1); - } - else { - userInfo = ""; - hostAndPort = authority; - } + size_t atIndex = authority.find('@'); + std::string userInfo; + std::string hostAndPort; + if (atIndex != std::string::npos) { + userInfo = authority.substr(0, atIndex); + hostAndPort = authority.substr(atIndex + 1); + } + else { + userInfo = ""; + hostAndPort = authority; + } - 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)); - } - catch (const boost::bad_lexical_cast&) { - return URL(); - } - } - else { - host = unescape(hostAndPort); - } + std::string host; + boost::optional<int> port; + 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(); + } + } + } + else { + return URL(); + } + } + else { + 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) { - return URL(scheme, host, *port, path); - } - else { - return URL(scheme, host, path); - } - } - else { - // We don't support URLs without authorities yet - return URL(); - } + if (port) { + return URL(scheme, host, *port, path); + } + else { + return URL(scheme, host, path); + } + } + else { + // We don't support URLs without authorities yet + return URL(); + } } // FIXME: Escape non-ascii characters std::string URL::toString() const { - if (empty) { - return ""; - } - std::string result = scheme + "://"; - if (!user.empty()) { - result += user; - if (!password.empty()) { - result += ":" + password; - } - result += "@"; - } - result += host; - if (port) { - result += ":"; - result += boost::lexical_cast<std::string>(*port); - } - result += path; - return result; + if (empty) { + return ""; + } + std::string result = scheme + "://"; + if (!user.empty()) { + result += user; + if (!password.empty()) { + result += ":" + password; + } + result += "@"; + } + if (host.find(':') != std::string::npos) { + result += "[" + host + "]"; + } + else { + result += host; + } + if (port) { + result += ":"; + result += boost::lexical_cast<std::string>(*port); + } + result += path; + return result; } // Disabling this code for now, since GCC4.5+boost1.42 (on ubuntu) seems to @@ -118,72 +145,72 @@ std::string URL::toString() const { struct PercentEncodedCharacterFinder { template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { - boost::iterator_range<Iterator> r = boost::first_finder("%")(begin, end); - if (r.end() == end) { - return r; - } - else { - if (r.end() + 1 == end || r.end() + 2 == end) { - throw std::runtime_error("Incomplete escape character"); - } - else { - r.advance_end(2); - return r; - } - } + boost::iterator_range<Iterator> r = boost::first_finder("%")(begin, end); + if (r.end() == end) { + return r; + } + else { + if (r.end() + 1 == end || r.end() + 2 == end) { + throw std::runtime_error("Incomplete escape character"); + } + else { + r.advance_end(2); + return r; + } + } } }; struct PercentUnencodeFormatter { template<typename FindResult> std::string operator()(const FindResult& match) const { - std::stringstream s; - s << std::hex << std::string(match.begin() + 1, match.end()); - unsigned int value; - s >> value; - if (s.fail() || s.bad()) { - throw std::runtime_error("Invalid escape character"); - } - unsigned char charValue = static_cast<unsigned char>(value); - return std::string(reinterpret_cast<const char*>(&charValue), 1); + std::stringstream s; + s << std::hex << std::string(match.begin() + 1, match.end()); + unsigned int value; + s >> value; + if (s.fail() || s.bad()) { + throw std::runtime_error("Invalid escape character"); + } + unsigned char charValue = static_cast<unsigned char>(value); + return std::string(reinterpret_cast<const char*>(&charValue), 1); } }; std::string unescape(const std::string& s) { - try { - return boost::find_format_all_copy(s, PercentEncodedCharacterFinder(), PercentUnencodeFormatter()); - } - catch (const std::exception&) { - return ""; - } + try { + return boost::find_format_all_copy(s, PercentEncodedCharacterFinder(), PercentUnencodeFormatter()); + } + catch (const std::exception&) { + return ""; + } } #endif std::string URL::unescape(const std::string& str) { - std::string result; - for (size_t i = 0; i < str.size(); ++i) { - if (str[i] == '%') { - if (i + 3 < str.size()) { - std::stringstream s; - s << std::hex << str.substr(i+1, 2); - unsigned int value; - s >> value; - if (s.fail() || s.bad()) { - return ""; - } - unsigned char charValue = static_cast<unsigned char>(value); - result += std::string(reinterpret_cast<const char*>(&charValue), 1); - i += 2; - } - else { - return ""; - } - } - else { - result += str[i]; - } - } - return result; + std::string result; + for (size_t i = 0; i < str.size(); ++i) { + if (str[i] == '%') { + if (i + 3 < str.size()) { + std::stringstream s; + s << std::hex << str.substr(i+1, 2); + unsigned int value; + s >> value; + if (s.fail() || s.bad()) { + return ""; + } + unsigned char charValue = static_cast<unsigned char>(value); + result += std::string(reinterpret_cast<const char*>(&charValue), 1); + i += 2; + } + else { + return ""; + } + } + else { + result += str[i]; + } + } + return result; } } |