diff options
-rw-r--r-- | src/Uri.cpp | 63 | ||||
-rw-r--r-- | test/src/UriTests.cpp | 36 |
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; + } +} |