diff --git a/base/base_tests/CMakeLists.txt b/base/base_tests/CMakeLists.txt
index 1b69fab526..628b4bea9c 100644
--- a/base/base_tests/CMakeLists.txt
+++ b/base/base_tests/CMakeLists.txt
@@ -48,6 +48,7 @@ set(
timegm_test.cpp
timer_test.cpp
uni_string_dfa_test.cpp
+ url_helpers_tests.cpp
visitor_tests.cpp
)
diff --git a/base/base_tests/url_helpers_tests.cpp b/base/base_tests/url_helpers_tests.cpp
new file mode 100644
index 0000000000..dead198d4e
--- /dev/null
+++ b/base/base_tests/url_helpers_tests.cpp
@@ -0,0 +1,14 @@
+#include "testing/testing.hpp"
+
+#include "base/url_helpers.hpp"
+
+UNIT_TEST(Url_Join)
+{
+ TEST_EQUAL("", base::url::Join("", ""), ());
+ TEST_EQUAL("omim/strings", base::url::Join("omim", "strings"), ());
+ TEST_EQUAL("omim/strings", base::url::Join("omim/", "strings"), ());
+ TEST_EQUAL("../../omim/strings", base::url::Join("..", "..", "omim", "strings"), ());
+ TEST_EQUAL("../../omim/strings", base::url::Join("../", "..", "omim/", "strings"), ());
+ TEST_EQUAL("omim/strings", base::url::Join("omim/", "/strings"), ());
+ TEST_EQUAL("../../omim/strings", base::url::Join("../", "/../", "/omim/", "/strings"), ());
+}
diff --git a/base/url_helpers.cpp b/base/url_helpers.cpp
index a53cc82445..e8b6d53aa5 100644
--- a/base/url_helpers.cpp
+++ b/base/url_helpers.cpp
@@ -31,5 +31,21 @@ string Make(string const & baseUrl, Params const & params)
return os.str();
}
+
+std::string Join(std::string const & lhs, std::string const & rhs)
+{
+ if (lhs.empty())
+ return rhs;
+ if (rhs.empty())
+ return lhs;
+
+ if (lhs.back() == '/' && rhs.front() == '/')
+ return lhs + rhs.substr(1);
+
+ if (lhs.back() != '/' && rhs.front() != '/')
+ return lhs + '/' + rhs;
+
+ return lhs + rhs;
+}
} // namespace url
} // namespace base
diff --git a/base/url_helpers.hpp b/base/url_helpers.hpp
index ce27431a09..466cf4e913 100644
--- a/base/url_helpers.hpp
+++ b/base/url_helpers.hpp
@@ -20,5 +20,19 @@ using Params = std::vector;
// Make URL by using base url and vector of params.
std::string Make(std::string const & baseUrl, Params const & params);
+
+// Joins URL, appends/removes slashes if needed.
+std::string Join(std::string const & lhs, std::string const & rhs);
+
+template
+std::string Join(std::string const & lhs, std::string const & rhs, Args &&... args)
+{
+ if (lhs.empty())
+ return Join(rhs, std::forward(args)...);
+ if (rhs.empty())
+ return Join(lhs, std::forward(args)...);
+
+ return Join(Join(lhs, rhs), std::forward(args)...);
+}
} // namespace url
} // namespace base