diff options
-rw-r--r-- | cmake/test-files.cmake | 1 | ||||
-rw-r--r-- | src/mbgl/util/url.cpp | 35 | ||||
-rw-r--r-- | src/mbgl/util/url.hpp | 1 | ||||
-rw-r--r-- | test/util/url.test.cpp | 25 |
4 files changed, 60 insertions, 2 deletions
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index ceff50ef64..7d8dc82756 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -112,5 +112,6 @@ set(MBGL_TEST_FILES test/util/tile_cover.test.cpp test/util/timer.test.cpp test/util/token.test.cpp + test/util/url.test.cpp test/util/work_queue.test.cpp ) diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp index bf6fc70ff5..9831bc9038 100644 --- a/src/mbgl/util/url.cpp +++ b/src/mbgl/util/url.cpp @@ -1,12 +1,30 @@ #include <mbgl/util/url.hpp> -#include <cctype> #include <iomanip> #include <sstream> #include <string> #include <cstdlib> #include <algorithm> + +namespace { + +// std::alnum etc. suffer from locale-dependence. + +inline bool isAlphaCharacter(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +inline bool isAlphaNumericCharacter(char c) { + return isAlphaCharacter(c) || (c >= '0' && c <= '9'); +} + +inline bool isSchemeCharacter(char c) { + return isAlphaNumericCharacter(c) || c == '-' || c == '+' || c == '.'; +} + +} // namespace + namespace mbgl { namespace util { @@ -17,7 +35,7 @@ std::string percentEncode(const std::string& input) { encoded << std::hex; for (auto c : input) { - if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + if (isAlphaNumericCharacter(c) || c == '-' || c == '_' || c == '.' || c == '~') { encoded << c; } else { encoded << '%' << std::setw(2) << int(c); @@ -47,5 +65,18 @@ std::string percentDecode(const std::string& input) { return decoded; } +// Checks whether the input string contains ://, and the part before it is all alphanumeric ASCII. +bool isURL(const std::string& input) { + auto it = input.begin(); + // First character has to be alphabetic + if (it == input.end() || !isAlphaCharacter(*it++)) return false; + // The remaining characters of the scheme can be alphanumeric, or be one of +.- + while (it != input.end() && isSchemeCharacter(*it)) ++it; + // Check that :// follows + return (it != input.end() && *it++ == ':') && + (it != input.end() && *it++ == '/') && + (it != input.end() && *it++ == '/'); +} + } // namespace util } // namespace mbgl diff --git a/src/mbgl/util/url.hpp b/src/mbgl/util/url.hpp index b9c66261df..2d18f7476a 100644 --- a/src/mbgl/util/url.hpp +++ b/src/mbgl/util/url.hpp @@ -8,6 +8,7 @@ namespace util { std::string percentEncode(const std::string&); std::string percentDecode(const std::string&); +bool isURL(const std::string&); } // namespace util } // namespace mbgl diff --git a/test/util/url.test.cpp b/test/util/url.test.cpp new file mode 100644 index 0000000000..c0ee30efab --- /dev/null +++ b/test/util/url.test.cpp @@ -0,0 +1,25 @@ +#include <mbgl/test/util.hpp> + +#include <mbgl/util/url.hpp> + +#include <memory> + +using namespace mbgl::util; + +TEST(URL, isURL) { + EXPECT_TRUE(isURL("mapbox://foo")); + EXPECT_TRUE(isURL("mapbox://")); + EXPECT_TRUE(isURL("mapbox-test-scheme://foo")); + EXPECT_TRUE(isURL("mapbox+style://foo")); + EXPECT_TRUE(isURL("mapbox-2.0://foo")); + EXPECT_TRUE(isURL("mapbox99://foo")); + + EXPECT_FALSE(isURL("mapbox:/")); + EXPECT_FALSE(isURL(" mapbox://")); + EXPECT_FALSE(isURL("://")); + EXPECT_FALSE(isURL("mapbox")); + EXPECT_FALSE(isURL("mapbox:foo")); + EXPECT_FALSE(isURL("mapbox:/foo")); + EXPECT_FALSE(isURL("test/mapbox://foo")); + EXPECT_FALSE(isURL("123://foo")); +} |