| #include "utility.hpp" | |
| #include <cstdint> | |
| #include <functional> | |
| #include <string> | |
| #include <string_view> | |
| #include <gtest/gtest.h> // IWYU pragma: keep | |
| #include "boost/url/error.hpp" | |
| #include "boost/url/url.hpp" | |
| #include "boost/url/url_view.hpp" | |
| #include "bmcweb_config.h" | |
| #include <nlohmann/json.hpp> | |
| // IWYU pragma: no_include <gtest/gtest-message.h> | |
| // IWYU pragma: no_include <gtest/gtest-test-part.h> | |
| // IWYU pragma: no_include "gtest/gtest_pred_impl.h" | |
| namespace crow::utility { | |
| namespace { | |
| using ::crow::black_magic::getParameterTag; | |
| TEST(Utility, Base64DecodeAuthString) { | |
| std::string authString("dXNlcm40bWU6cGFzc3cwcmQ="); | |
| std::string result; | |
| EXPECT_TRUE(base64Decode(authString, result)); | |
| EXPECT_EQ(result, "usern4me:passw0rd"); | |
| } | |
| TEST(Utility, Base64DecodeNonAscii) { | |
| std::string junkString("\xff\xee\xdd\xcc\x01\x11\x22\x33"); | |
| std::string result; | |
| EXPECT_FALSE(base64Decode(junkString, result)); | |
| } | |
| TEST(Utility, Base64EncodeString) { | |
| using namespace std::string_literals; // NOLINT | |
| std::string encoded; | |
| encoded = base64encode(""); | |
| EXPECT_EQ(encoded, ""); | |
| encoded = base64encode("f"); | |
| EXPECT_EQ(encoded, "Zg=="); | |
| encoded = base64encode("f0"); | |
| EXPECT_EQ(encoded, "ZjA="); | |
| encoded = base64encode("f0\0"s); | |
| EXPECT_EQ(encoded, "ZjAA"); | |
| encoded = base64encode("f0\0 "s); | |
| EXPECT_EQ(encoded, "ZjAAIA=="); | |
| encoded = base64encode("f0\0 B"s); | |
| EXPECT_EQ(encoded, "ZjAAIEI="); | |
| encoded = base64encode("f0\0 Ba"s); | |
| EXPECT_EQ(encoded, "ZjAAIEJh"); | |
| encoded = base64encode("f0\0 Bar"s); | |
| EXPECT_EQ(encoded, "ZjAAIEJhcg=="); | |
| } | |
| TEST(Utility, Base64EncodeDecodeString) { | |
| using namespace std::string_literals; // NOLINT | |
| std::string data("Data fr\0m 90 reading a \nFile"s); | |
| std::string encoded = base64encode(data); | |
| std::string decoded; | |
| EXPECT_TRUE(base64Decode(encoded, decoded)); | |
| EXPECT_EQ(data, decoded); | |
| } | |
| TEST(Utility, UrlFromPieces) { | |
| boost::urls::url url = urlFromPieces("redfish", "v1", "foo"); | |
| EXPECT_EQ(url.buffer(), "/redfish/v1/foo"); | |
| url = urlFromPieces("/", "badString"); | |
| EXPECT_EQ(url.buffer(), "/%2F/badString"); | |
| url = urlFromPieces("bad?tring"); | |
| EXPECT_EQ(url.buffer(), "/bad%3Ftring"); | |
| url = urlFromPieces("/", "bad&tring"); | |
| EXPECT_EQ(url.buffer(), "/%2F/bad&tring"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), "/%2F/bad&tring"); | |
| url = urlFromPieces("my-user"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), "/my-user"); | |
| url = urlFromPieces("my_user"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), "/my_user"); | |
| url = urlFromPieces("my_93user"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), "/my_93user"); | |
| // The following characters will be converted to ASCII number | |
| // `[{]}\|"<>/?#%^ | |
| url = urlFromPieces("~1234567890-_=+qwertyuiopasdfghjklzxcvbnm;:',.!@$&*()"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), | |
| "/~1234567890-_=+qwertyuiopasdfghjklzxcvbnm;:',.!@$&*()"); | |
| } | |
| TEST(Utility, readUrlSegments) { | |
| auto parsed = | |
| boost::urls::parse_relative_ref("/redfish/v1/Chassis#/Fans/0/Reading"); | |
| EXPECT_TRUE(readUrlSegments(*parsed, "redfish", "v1", "Chassis")); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "FOOBAR", "v1", "Chassis")); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "redfish", "v1")); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "redfish", "v1", "Chassis", "FOOBAR")); | |
| std::string out1; | |
| std::string out2; | |
| std::string out3; | |
| EXPECT_TRUE(readUrlSegments(*parsed, "redfish", "v1", std::ref(out1))); | |
| EXPECT_EQ(out1, "Chassis"); | |
| out1 = out2 = out3 = ""; | |
| EXPECT_TRUE( | |
| readUrlSegments(*parsed, std::ref(out1), std::ref(out2), std::ref(out3))); | |
| EXPECT_EQ(out1, "redfish"); | |
| EXPECT_EQ(out2, "v1"); | |
| EXPECT_EQ(out3, "Chassis"); | |
| out1 = out2 = out3 = ""; | |
| EXPECT_TRUE(readUrlSegments(*parsed, "redfish", std::ref(out1), "Chassis")); | |
| EXPECT_EQ(out1, "v1"); | |
| out1 = out2 = out3 = ""; | |
| EXPECT_TRUE(readUrlSegments(*parsed, std::ref(out1), "v1", std::ref(out2))); | |
| EXPECT_EQ(out1, "redfish"); | |
| EXPECT_EQ(out2, "Chassis"); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "too", "short")); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "too", "long", "too", "long")); | |
| EXPECT_FALSE(readUrlSegments(*parsed, std::ref(out1), "v2", std::ref(out2))); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "redfish", std::ref(out1), | |
| std::ref(out2), std::ref(out3))); | |
| parsed = boost::urls::parse_relative_ref("/absolute/url"); | |
| EXPECT_TRUE(readUrlSegments(*parsed, "absolute", "url")); | |
| parsed = boost::urls::parse_relative_ref("not/absolute/url"); | |
| EXPECT_FALSE(readUrlSegments(*parsed, "not", "absolute", "url")); | |
| parsed = boost::urls::parse_relative_ref("/excellent/path"); | |
| EXPECT_TRUE(readUrlSegments(*parsed, "excellent", "path", OrMorePaths())); | |
| EXPECT_TRUE(readUrlSegments(*parsed, "excellent", OrMorePaths())); | |
| EXPECT_TRUE(readUrlSegments(*parsed, OrMorePaths())); | |
| } | |
| TEST(Utility, ValidateAndSplitUrlPositive) { | |
| std::string host; | |
| std::string urlProto; | |
| uint16_t port = 0; | |
| std::string path; | |
| ASSERT_TRUE(validateAndSplitUrl("https://foo.com:18080/bar", urlProto, host, | |
| port, path)); | |
| EXPECT_EQ(host, "foo.com"); | |
| EXPECT_EQ(urlProto, "https"); | |
| EXPECT_EQ(port, 18080); | |
| EXPECT_EQ(path, "/bar"); | |
| // query string | |
| ASSERT_TRUE(validateAndSplitUrl("https://foo.com:18080/bar?foobar=1", | |
| urlProto, host, port, path)); | |
| EXPECT_EQ(path, "/bar?foobar=1"); | |
| // fragment | |
| ASSERT_TRUE(validateAndSplitUrl("https://foo.com:18080/bar#frag", urlProto, | |
| host, port, path)); | |
| EXPECT_EQ(path, "/bar#frag"); | |
| // Missing port | |
| ASSERT_TRUE( | |
| validateAndSplitUrl("https://foo.com/bar", urlProto, host, port, path)); | |
| EXPECT_EQ(port, 443); | |
| // Missing path defaults to "/" | |
| ASSERT_TRUE( | |
| validateAndSplitUrl("https://foo.com/", urlProto, host, port, path)); | |
| EXPECT_EQ(path, "/"); | |
| // If http push eventing is allowed, allow http and pick a default port of | |
| // 80, if it's not, parse should fail. | |
| ASSERT_EQ( | |
| validateAndSplitUrl("http://foo.com/bar", urlProto, host, port, path), | |
| bmcwebInsecureEnableHttpPushStyleEventing); | |
| if constexpr (bmcwebInsecureEnableHttpPushStyleEventing) { | |
| EXPECT_EQ(port, 80); | |
| } | |
| } | |
| TEST(Router, ParameterTagging) { | |
| EXPECT_EQ(6 * 6 + 6 * 3 + 2, getParameterTag("<uint><double><int>")); | |
| EXPECT_EQ(1, getParameterTag("<int>")); | |
| EXPECT_EQ(2, getParameterTag("<uint>")); | |
| EXPECT_EQ(3, getParameterTag("<float>")); | |
| EXPECT_EQ(3, getParameterTag("<double>")); | |
| EXPECT_EQ(4, getParameterTag("<str>")); | |
| EXPECT_EQ(4, getParameterTag("<string>")); | |
| EXPECT_EQ(5, getParameterTag("<path>")); | |
| EXPECT_EQ(6 * 6 + 6 + 1, getParameterTag("<int><int><int>")); | |
| EXPECT_EQ(6 * 6 + 6 + 2, getParameterTag("<uint><int><int>")); | |
| EXPECT_EQ(6 * 6 + 6 * 3 + 2, getParameterTag("<uint><double><int>")); | |
| } | |
| TEST(URL, JsonEncoding) { | |
| std::string urlString = "/foo"; | |
| EXPECT_EQ(nlohmann::json(boost::urls::url(urlString)), urlString); | |
| EXPECT_EQ(nlohmann::json(boost::urls::url_view(urlString)), urlString); | |
| } | |
| TEST(URL, UrlToJsonCorrectlyDecodesPercentEscapeSequences) { | |
| nlohmann::json json; | |
| json["test"] = boost::urls::url("%2F"); | |
| EXPECT_EQ(json["test"], "/"); | |
| } | |
| TEST(URL, UrlViewToJsonCorrectlyDecodesPercentEscapeSequences) { | |
| nlohmann::json json; | |
| json["test"] = boost::urls::url_view("%2F"); | |
| EXPECT_EQ(json["test"], "/"); | |
| } | |
| TEST(URL, UrlToJsonCorrectlyOutputsFragments) { | |
| nlohmann::json json; | |
| json["test"] = boost::urls::url_view("%2Ftest#%2F"); | |
| EXPECT_EQ(json["test"], "/test#/"); | |
| } | |
| TEST(AppendUrlFromPieces, PiecesAreAppendedViaDelimiters) { | |
| boost::urls::url url = urlFromPieces("redfish", "v1", "foo"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), "/redfish/v1/foo"); | |
| appendUrlPieces(url, "bar"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), "/redfish/v1/foo/bar"); | |
| appendUrlPieces(url, "/", "bad&tring"); | |
| EXPECT_EQ(std::string_view(url.data(), url.size()), | |
| "/redfish/v1/foo/bar/%2F/bad&tring"); | |
| } | |
| } // namespace | |
| } // namespace crow::utility |