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