aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Uri.cpp63
-rw-r--r--test/src/UriTests.cpp36
2 files changed, 97 insertions, 2 deletions
diff --git a/src/Uri.cpp b/src/Uri.cpp
index 5c4002d..1a82ee8 100644
--- a/src/Uri.cpp
+++ b/src/Uri.cpp
@@ -237,11 +237,70 @@ namespace Uri {
// Next, check if there is a UserInfo, and if so, extract it.
const auto userInfoDelimiter = authorityString.find('@');
std::string hostPortString;
+ userInfo.clear();
if (userInfoDelimiter == std::string::npos) {
- userInfo.clear();
hostPortString = authorityString;
} else {
- userInfo = authorityString.substr(0, userInfoDelimiter);
+ const auto userInfoEncoded = authorityString.substr(0, userInfoDelimiter);
+ size_t decoderState = 0;
+ int decodedCharacter = 0;
+ for (const auto c: userInfoEncoded) {
+ switch(decoderState) {
+ case 0: { // default
+ if (c == '%') {
+ decoderState = 1;
+ } else {
+ if (
+ IsCharacterInSet(
+ c,
+ {
+ // unreserved
+ 'a','z', 'A','Z', // ALPHA
+ '0','9', // DIGIT
+ '-','-', '.','.', '_','_', '~','~',
+
+ // sub-delims
+ '!','!', '$','$', '&','&', '\'','\'', '(','(', ')',')',
+ '*','*', '+','+', ',',',', ';',';', '=','=',
+
+ // (also allowed in userinfo)
+ ':',':',
+ }
+ )
+ ) {
+ userInfo.push_back(c);
+ } else {
+ return false;
+ }
+ }
+ } break;
+
+ case 1: { // % ...
+ decoderState = 2;
+ decodedCharacter <<= 4;
+ if (IsCharacterInSet(c, {'0','9'})) {
+ decodedCharacter += (int)(c - '0');
+ } else if (IsCharacterInSet(c, {'A','F'})) {
+ decodedCharacter += (int)(c - 'A') + 10;
+ } else {
+ return false;
+ }
+ } break;
+
+ case 2: { // %[0-9A-F] ...
+ decoderState = 0;
+ decodedCharacter <<= 4;
+ if (IsCharacterInSet(c, {'0','9'})) {
+ decodedCharacter += (int)(c - '0');
+ } else if (IsCharacterInSet(c, {'A','F'})) {
+ decodedCharacter += (int)(c - 'A') + 10;
+ } else {
+ return false;
+ }
+ userInfo.push_back((char)decodedCharacter);
+ } break;
+ }
+ }
hostPortString = authorityString.substr(userInfoDelimiter + 1);
}
diff --git a/test/src/UriTests.cpp b/test/src/UriTests.cpp
index b4be2d5..d246a4d 100644
--- a/test/src/UriTests.cpp
+++ b/test/src/UriTests.cpp
@@ -274,3 +274,39 @@ TEST(UriTests, ParseFromStringSchemeBarelyLegal) {
++index;
}
}
+
+TEST(UriTests, ParseFromStringUserInfoIllegalCharacters) {
+ const std::vector< std::string > testVectors{
+ {"//%X@www.example.com/"},
+ {"//{@www.example.com/"},
+ };
+ size_t index = 0;
+ for (const auto& testVector : testVectors) {
+ Uri::Uri uri;
+ ASSERT_FALSE(uri.ParseFromString(testVector)) << index;
+ ++index;
+ }
+}
+
+TEST(UriTests, ParseFromStringUserInfoBarelyLegal) {
+ struct TestVector {
+ std::string uriString;
+ std::string userInfo;
+ };
+ const std::vector< TestVector > testVectors{
+ {"//%41@www.example.com/", "A"},
+ {"//@www.example.com/", ""},
+ {"//!@www.example.com/", "!"},
+ {"//'@www.example.com/", "'"},
+ {"//(@www.example.com/", "("},
+ {"//;@www.example.com/", ";"},
+ {"http://:@www.example.com/", ":"},
+ };
+ size_t index = 0;
+ for (const auto& testVector : testVectors) {
+ Uri::Uri uri;
+ ASSERT_TRUE(uri.ParseFromString(testVector.uriString)) << index;
+ ASSERT_EQ(testVector.userInfo, uri.GetUserInfo());
+ ++index;
+ }
+}