aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Walters <rwalters@digitalstirling.com>2018-06-30 23:35:15 -0700
committerRichard Walters <rwalters@digitalstirling.com>2018-06-30 23:35:15 -0700
commitb57bf0b772c5cfef789363b9951f737d9e92a28a (patch)
tree369f2d034a9ae4862674d73ced46a9df3714a65e
parent6f389efe5808c83f86a4c71861c50e6e941fc5bb (diff)
Add code to check that scheme, if present, is legal
-rw-r--r--src/Uri.cpp88
-rw-r--r--test/src/UriTests.cpp39
2 files changed, 127 insertions, 0 deletions
diff --git a/src/Uri.cpp b/src/Uri.cpp
index 8bc2f4a..da1b9f8 100644
--- a/src/Uri.cpp
+++ b/src/Uri.cpp
@@ -6,7 +6,9 @@
* © 2018 by Richard Walters
*/
+#include <functional>
#include <inttypes.h>
+#include <memory>
#include <string>
#include <Uri/Uri.hpp>
#include <vector>
@@ -51,6 +53,83 @@ namespace {
return true;
}
+ /**
+ * This function takes a given "stillPassing" strategy
+ * and invokes it on the sequence of characters in the given
+ * string, to check if the string passes or not.
+ *
+ * @param[in] candidate
+ * This is the string to test.
+ *
+ * @param[in] stillPassing
+ * This is the strategy to invoke in order to test the string.
+ *
+ * @return
+ * An indication of whether or not the given candidate string
+ * passes the test is returned.
+ */
+ bool FailsMatch(
+ const std::string& candidate,
+ std::function< bool(char, bool) > stillPassing
+ ) {
+ for (const auto c: candidate) {
+ if (!stillPassing(c, false)) {
+ return true;
+ }
+ }
+ return !stillPassing(' ', true);
+ }
+
+ /**
+ * This function returns a strategy function that
+ * may be used with the FailsMatch function to test a scheme
+ * to make sure it is legal according to the standard.
+ *
+ * @return
+ * A strategy function that may be used with the
+ * FailsMatch function to test a scheme to make sure
+ * it is legal according to the standard is returned.
+ */
+ std::function< bool(char, bool) > LegalSchemeCheckStrategy() {
+ auto isFirstCharacter = std::make_shared< bool >(true);
+ return [isFirstCharacter](char c, bool end){
+ if (end) {
+ return !*isFirstCharacter;
+ } else {
+ bool check;
+ if (*isFirstCharacter) {
+ check = (
+ (
+ (c >= 'a')
+ && (c <= 'z')
+ ) || (
+ (c >= 'A')
+ && (c <= 'Z')
+ )
+ );
+ } else {
+ check = (
+ (
+ (c >= 'a')
+ && (c <= 'z')
+ ) || (
+ (c >= 'A')
+ && (c <= 'Z')
+ ) || (
+ (c >= '0')
+ && (c <= '9')
+ )
+ || (c == '+')
+ || (c == '-')
+ || (c == '.')
+ );
+ }
+ *isFirstCharacter = false;
+ return check;
+ }
+ };
+ }
+
}
namespace Uri {
@@ -200,6 +279,15 @@ namespace Uri {
rest = uriString;
} else {
impl_->scheme = uriString.substr(0, schemeEnd);
+ bool isFirstCharacter = true;
+ if (
+ FailsMatch(
+ impl_->scheme,
+ LegalSchemeCheckStrategy()
+ )
+ ) {
+ return false;
+ }
rest = uriString.substr(schemeEnd + 1);
}
diff --git a/test/src/UriTests.cpp b/test/src/UriTests.cpp
index 6ee57c4..b4be2d5 100644
--- a/test/src/UriTests.cpp
+++ b/test/src/UriTests.cpp
@@ -235,3 +235,42 @@ TEST(UriTests, ParseFromStringTwiceFirstUserInfoThenWithout) {
ASSERT_TRUE(uri.ParseFromString("/foo/bar"));
ASSERT_TRUE(uri.GetUserInfo().empty());
}
+
+TEST(UriTests, ParseFromStringSchemeIllegalCharacters) {
+ const std::vector< std::string > testVectors{
+ {"://www.example.com/"},
+ {"0://www.example.com/"},
+ {"+://www.example.com/"},
+ {"@://www.example.com/"},
+ {".://www.example.com/"},
+ {"h@://www.example.com/"},
+ };
+ size_t index = 0;
+ for (const auto& testVector : testVectors) {
+ Uri::Uri uri;
+ ASSERT_FALSE(uri.ParseFromString(testVector)) << index;
+ ++index;
+ }
+}
+
+TEST(UriTests, ParseFromStringSchemeBarelyLegal) {
+ struct TestVector {
+ std::string uriString;
+ std::string scheme;
+ };
+ const std::vector< TestVector > testVectors{
+ {"h://www.example.com/", "h"},
+ {"x+://www.example.com/", "x+"},
+ {"y-://www.example.com/", "y-"},
+ {"z.://www.example.com/", "z."},
+ {"aa://www.example.com/", "aa"},
+ {"a0://www.example.com/", "a0"},
+ };
+ size_t index = 0;
+ for (const auto& testVector : testVectors) {
+ Uri::Uri uri;
+ ASSERT_TRUE(uri.ParseFromString(testVector.uriString)) << index;
+ ASSERT_EQ(testVector.scheme, uri.GetScheme());
+ ++index;
+ }
+}