1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 4 #include "utility.hpp" 5 6 #include <boost/system/result.hpp> 7 #include <boost/url/parse.hpp> 8 #include <boost/url/url.hpp> 9 #include <boost/url/url_view.hpp> 10 #include <nlohmann/json.hpp> 11 12 #include <algorithm> 13 #include <ctime> 14 #include <functional> 15 #include <string> 16 #include <string_view> 17 18 #include <gtest/gtest.h> 19 20 namespace crow::utility 21 { 22 namespace 23 { 24 25 using ::crow::utility::getParameterTag; 26 27 TEST(Utility, Base64DecodeAuthString) 28 { 29 std::string authString("dXNlcm40bWU6cGFzc3cwcmQ="); 30 std::string result; 31 EXPECT_TRUE(base64Decode(authString, result)); 32 EXPECT_EQ(result, "usern4me:passw0rd"); 33 } 34 35 TEST(Utility, Base64DecodeUrlsafe) 36 { 37 std::string result; 38 EXPECT_TRUE(base64Decode<true>("-_abcde", result)); 39 EXPECT_EQ(result, "\xfb\xf6\x9b\x71\xd7"); 40 } 41 42 TEST(Utility, Base64DecodeNonAscii) 43 { 44 std::string junkString("\xff\xee\xdd\xcc\x01\x11\x22\x33"); 45 std::string result; 46 EXPECT_FALSE(base64Decode(junkString, result)); 47 } 48 49 TEST(Utility, Base64EncodeString) 50 { 51 using namespace std::string_literals; 52 std::string encoded; 53 54 encoded = base64encode(""); 55 EXPECT_EQ(encoded, ""); 56 57 encoded = base64encode("f"); 58 EXPECT_EQ(encoded, "Zg=="); 59 60 encoded = base64encode("f0"); 61 EXPECT_EQ(encoded, "ZjA="); 62 63 encoded = base64encode("f0\0"s); 64 EXPECT_EQ(encoded, "ZjAA"); 65 66 encoded = base64encode("f0\0 "s); 67 EXPECT_EQ(encoded, "ZjAAIA=="); 68 69 encoded = base64encode("f0\0 B"s); 70 EXPECT_EQ(encoded, "ZjAAIEI="); 71 72 encoded = base64encode("f0\0 Ba"s); 73 EXPECT_EQ(encoded, "ZjAAIEJh"); 74 75 encoded = base64encode("f0\0 Bar"s); 76 EXPECT_EQ(encoded, "ZjAAIEJhcg=="); 77 } 78 79 TEST(Utility, Base64Encoder) 80 { 81 using namespace std::string_literals; 82 std::string data = "f0\0 Bar"s; 83 for (size_t chunkSize = 1; chunkSize < 6; chunkSize++) 84 { 85 std::string_view testString(data); 86 std::string out; 87 Base64Encoder encoder; 88 while (!testString.empty()) 89 { 90 size_t thisChunk = std::min(testString.size(), chunkSize); 91 encoder.encode(testString.substr(0, thisChunk), out); 92 testString.remove_prefix(thisChunk); 93 } 94 95 encoder.finalize(out); 96 EXPECT_EQ(out, "ZjAAIEJhcg=="); 97 } 98 } 99 100 TEST(Utility, Base64EncodeDecodeString) 101 { 102 using namespace std::string_literals; 103 std::string data("Data fr\0m 90 reading a \nFile"s); 104 std::string encoded = base64encode(data); 105 std::string decoded; 106 EXPECT_TRUE(base64Decode(encoded, decoded)); 107 EXPECT_EQ(data, decoded); 108 } 109 110 TEST(Utility, readUrlSegments) 111 { 112 boost::system::result<boost::urls::url_view> parsed = 113 boost::urls::parse_relative_ref("/redfish/v1/Chassis#/Fans/0/Reading"); 114 115 EXPECT_TRUE(readUrlSegments(*parsed, "redfish", "v1", "Chassis")); 116 117 EXPECT_FALSE(readUrlSegments(*parsed, "FOOBAR", "v1", "Chassis")); 118 119 EXPECT_FALSE(readUrlSegments(*parsed, "redfish", "v1")); 120 121 EXPECT_FALSE( 122 readUrlSegments(*parsed, "redfish", "v1", "Chassis", "FOOBAR")); 123 124 std::string out1; 125 std::string out2; 126 std::string out3; 127 EXPECT_TRUE(readUrlSegments(*parsed, "redfish", "v1", std::ref(out1))); 128 EXPECT_EQ(out1, "Chassis"); 129 130 out1 = out2 = out3 = ""; 131 EXPECT_TRUE(readUrlSegments(*parsed, std::ref(out1), std::ref(out2), 132 std::ref(out3))); 133 EXPECT_EQ(out1, "redfish"); 134 EXPECT_EQ(out2, "v1"); 135 EXPECT_EQ(out3, "Chassis"); 136 137 out1 = out2 = out3 = ""; 138 EXPECT_TRUE(readUrlSegments(*parsed, "redfish", std::ref(out1), "Chassis")); 139 EXPECT_EQ(out1, "v1"); 140 141 out1 = out2 = out3 = ""; 142 EXPECT_TRUE(readUrlSegments(*parsed, std::ref(out1), "v1", std::ref(out2))); 143 EXPECT_EQ(out1, "redfish"); 144 EXPECT_EQ(out2, "Chassis"); 145 146 EXPECT_FALSE(readUrlSegments(*parsed, "too", "short")); 147 148 EXPECT_FALSE(readUrlSegments(*parsed, "too", "long", "too", "long")); 149 150 EXPECT_FALSE( 151 readUrlSegments(*parsed, std::ref(out1), "v2", std::ref(out2))); 152 153 EXPECT_FALSE(readUrlSegments(*parsed, "redfish", std::ref(out1), 154 std::ref(out2), std::ref(out3))); 155 156 parsed = boost::urls::parse_relative_ref("/absolute/url"); 157 EXPECT_TRUE(readUrlSegments(*parsed, "absolute", "url")); 158 159 parsed = boost::urls::parse_relative_ref("not/absolute/url"); 160 EXPECT_FALSE(readUrlSegments(*parsed, "not", "absolute", "url")); 161 162 parsed = boost::urls::parse_relative_ref("/excellent/path"); 163 164 EXPECT_TRUE(readUrlSegments(*parsed, "excellent", "path", OrMorePaths())); 165 EXPECT_TRUE(readUrlSegments(*parsed, "excellent", OrMorePaths())); 166 EXPECT_TRUE(readUrlSegments(*parsed, OrMorePaths())); 167 } 168 169 TEST(Router, ParameterTagging) 170 { 171 EXPECT_EQ(1, getParameterTag("<str>")); 172 EXPECT_EQ(1, getParameterTag("<string>")); 173 EXPECT_EQ(1, getParameterTag("<path>")); 174 EXPECT_EQ(2, getParameterTag("<str>/<str>")); 175 EXPECT_EQ(2, getParameterTag("<string>/<string>")); 176 EXPECT_EQ(2, getParameterTag("<path>/<path>")); 177 } 178 179 TEST(URL, JsonEncoding) 180 { 181 std::string urlString = "/foo"; 182 EXPECT_EQ(nlohmann::json(boost::urls::url(urlString)), urlString); 183 EXPECT_EQ(nlohmann::json(boost::urls::url_view(urlString)), urlString); 184 } 185 186 TEST(AppendUrlFromPieces, PiecesAreAppendedViaDelimiters) 187 { 188 boost::urls::url url("/redfish/v1/foo"); 189 EXPECT_EQ(std::string_view(url.data(), url.size()), "/redfish/v1/foo"); 190 191 appendUrlPieces(url, "bar"); 192 EXPECT_EQ(std::string_view(url.data(), url.size()), "/redfish/v1/foo/bar"); 193 194 appendUrlPieces(url, "/", "bad&string"); 195 EXPECT_EQ(std::string_view(url.data(), url.size()), 196 "/redfish/v1/foo/bar/%2F/bad&string"); 197 } 198 199 } // namespace 200 } // namespace crow::utility 201