summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/JID/JID.cpp')
-rw-r--r--Swiften/JID/JID.cpp138
1 files changed, 76 insertions, 62 deletions
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp
index c82674d..eb72014 100644
--- a/Swiften/JID/JID.cpp
+++ b/Swiften/JID/JID.cpp
@@ -1,25 +1,19 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#define SWIFTEN_CACHE_JID_PREP
-
#include <sstream>
#include <string>
#include <vector>
-#ifdef SWIFTEN_CACHE_JID_PREP
-#include <mutex>
-#include <unordered_map>
-#endif
-
#include <boost/optional.hpp>
#include <Swiften/Base/String.h>
#include <Swiften/IDN/IDNConverter.h>
#include <Swiften/JID/JID.h>
+#include <Swiften/Network/HostAddress.h>
#ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER
#include <memory>
@@ -28,15 +22,6 @@
using namespace Swift;
-#ifdef SWIFTEN_CACHE_JID_PREP
-typedef std::unordered_map<std::string, std::string> PrepCache;
-
-static std::mutex namePrepCacheMutex;
-static PrepCache nodePrepCache;
-static PrepCache domainPrepCache;
-static PrepCache resourcePrepCache;
-#endif
-
static const std::vector<char> escapedChars = {' ', '"', '&', '\'', '/', '<', '>', '@', ':'};
static IDNConverter* idnConverter = nullptr;
@@ -87,6 +72,33 @@ JID::JID(const std::string& node, const std::string& domain, const std::string&
nameprepAndSetComponents(node, domain, resource);
}
+JID::JID(const JID& other) {
+ this->operator=(other);
+}
+
+JID::JID(JID&& other) {
+ this->operator=(std::move(other));
+}
+
+JID& JID::operator=(const JID& other) {
+ valid_ = other.valid_;
+ node_ = other.node_;
+ domain_ = other.domain_;
+ hasResource_ = other.hasResource_;
+ resource_ = other.resource_;
+ return *this;
+}
+
+JID& JID::operator=(JID&& other) {
+ valid_ = other.valid_;
+ other.valid_ = false;
+ node_ = std::move(other.node_);
+ domain_ = std::move(other.domain_);
+ hasResource_ = other.hasResource_;
+ resource_ = std::move(other.resource_);
+ return *this;
+}
+
void JID::initializeFromString(const std::string& jid) {
if (String::beginsWith(jid, '@')) {
valid_ = false;
@@ -104,74 +116,76 @@ void JID::initializeFromString(const std::string& jid) {
hasResource_ = false;
bare = jid;
}
- std::pair<std::string,std::string> nodeAndDomain = String::getSplittedAtFirst(bare, '@');
- if (nodeAndDomain.second.empty()) {
- nameprepAndSetComponents("", nodeAndDomain.first, resource);
+ auto firstMatch = bare.find('@');
+ if (firstMatch != bare.npos) {
+ nameprepAndSetComponents(bare.substr(0, firstMatch), bare.substr(firstMatch + 1), resource);
}
else {
- nameprepAndSetComponents(nodeAndDomain.first, nodeAndDomain.second, resource);
+ nameprepAndSetComponents("", bare, resource);
}
}
-
-void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) {
- if (domain.empty() || !idnConverter->getIDNAEncoded(domain)) {
+void JID::setComponents(const std::string& node, const std::string& domain, const std::string& resource) {
+ domain_ = domain;
+ try {
+ node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep);
+ resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep);
+ }
+ catch (...) {
valid_ = false;
return;
}
+}
- if (hasResource_ && resource.empty()) {
+void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) {
+ if (domain.empty() || (hasResource_ && resource.empty())) {
valid_ = false;
return;
}
-#ifndef SWIFTEN_CACHE_JID_PREP
- node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep);
- domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep);
- resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep);
-#else
- std::unique_lock<std::mutex> lock(namePrepCacheMutex);
-
- std::pair<PrepCache::iterator, bool> r;
-
- r = nodePrepCache.insert(std::make_pair(node, std::string()));
- if (r.second) {
- try {
- r.first->second = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep);
- }
- catch (...) {
- nodePrepCache.erase(r.first);
- valid_ = false;
+
+ // Handling IPv6 addresses according to RFC 3986 rules
+ // saying that they are enclosed in square brackets
+ // which we have to remove when passing to HostAddress
+ if (domain.size() > 2 && domain.front() == '[' && domain.back() == ']') {
+ auto inner = std::string(domain.begin() + 1, domain.end() - 1);
+ auto hostAddress = HostAddress::fromString(inner);
+ if (hostAddress && hostAddress->isValid()) {
+ setComponents(node, domain, resource);
return;
}
}
- node_ = r.first->second;
- r = domainPrepCache.insert(std::make_pair(domain, std::string()));
- if (r.second) {
- try {
- r.first->second = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep);
- }
- catch (...) {
- domainPrepCache.erase(r.first);
- valid_ = false;
+ const auto isAnyOfNonNumericAndNotDot = std::any_of(std::begin(domain), std::end(domain), [](char c) {return !::isdigit(c) && c != '.'; });
+ const auto isDomainAllNumeric = std::all_of(std::begin(domain), std::end(domain), [](char c) {return ::isdigit(c) ; });
+
+ //Prevent Windows validating non-dotted integers as OK if it can unpack them
+ if (!isAnyOfNonNumericAndNotDot && !isDomainAllNumeric) {
+ auto hostAddress = HostAddress::fromString(domain);
+ if (hostAddress && hostAddress->isValid()) {
+ setComponents(node, domain, resource);
return;
}
}
- domain_ = r.first->second;
- r = resourcePrepCache.insert(std::make_pair(resource, std::string()));
- if (r.second) {
- try {
- r.first->second = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep);
+ if (!isAnyOfNonNumericAndNotDot || !idnConverter->getIDNAEncoded(domain)) {
+ valid_ = false;
+ return;
+ }
+
+ try {
+ node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep);
+ if (domain.back() == '.') {
+ domain_ = idnConverter->getStringPrepared(domain.substr(0, domain.size() - 1), IDNConverter::NamePrep);
}
- catch (...) {
- resourcePrepCache.erase(r.first);
- valid_ = false;
- return;
+ else {
+ domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep);
}
+ resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep);
+ }
+ catch (...) {
+ valid_ = false;
+ return;
}
- resource_ = r.first->second;
-#endif
if (domain_.empty()) {
valid_ = false;