1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <fstream>
16
17 #include "contrib/uriparser/sandboxed.h"
18 #include "contrib/uriparser/utils/utils_uriparser.h"
19 #include "sandboxed_api/util/path.h"
20 #include "sandboxed_api/util/status_matchers.h"
21 #include "sandboxed_api/util/temp_file.h"
22
23 namespace {
24
25 using ::sapi::IsOk;
26
27 const struct TestVariant {
28 std::string test;
29 std::string uri;
30 std::string uriescaped;
31 std::string scheme;
32 std::string userinfo;
33 std::string hosttext;
34 std::string hostip;
35 std::string porttext;
36 std::string query;
37 std::string fragment;
38 std::string normalized;
39 std::string add_base_example;
40 std::string remove_base_example;
41 std::vector<std::string> path_elements;
42 std::map<std::string, std::string> query_elements;
43 } TestData[] = {
44 {
45 .test = "http://www.example.com/",
46 .uri = "http://www.example.com/",
47 .uriescaped = "http%3A%2F%2Fwww.example.com%2F",
48 .scheme = "http",
49 .userinfo = "",
50 .hosttext = "www.example.com",
51 .hostip = "",
52 .porttext = "",
53 .query = "",
54 .fragment = "",
55 .normalized = "http://www.example.com/",
56 .add_base_example = "http://www.example.com/",
57 .remove_base_example = "./",
58 },
59 {
60 .test = "https://github.com/google/sandboxed-api/",
61 .uri = "https://github.com/google/sandboxed-api/",
62 .uriescaped = "https%3A%2F%2Fgithub.com%2Fgoogle%2Fsandboxed-api%2F",
63 .scheme = "https",
64 .userinfo = "",
65 .hosttext = "github.com",
66 .hostip = "",
67 .porttext = "",
68 .query = "",
69 .fragment = "",
70 .normalized = "https://github.com/google/sandboxed-api/",
71 .add_base_example = "https://github.com/google/sandboxed-api/",
72 .remove_base_example = "https://github.com/google/sandboxed-api/",
73 .path_elements = {"google", "sandboxed-api"},
74 },
75 {
76 .test = "mailto:[email protected]",
77 .uri = "mailto:[email protected]",
78 .uriescaped = "mailto%3Atest%40example.com",
79 .scheme = "mailto",
80 .userinfo = "",
81 .hosttext = "",
82 .hostip = "",
83 .porttext = "",
84 .query = "",
85 .fragment = "",
86 .normalized = "mailto:[email protected]",
87 .add_base_example = "mailto:[email protected]",
88 .remove_base_example = "mailto:[email protected]",
89 .path_elements = {"[email protected]"},
90 },
91 {
92 .test = "file:///bin/bash",
93 .uri = "file:///bin/bash",
94 .uriescaped = "file%3A%2F%2F%2Fbin%2Fbash",
95 .scheme = "file",
96 .userinfo = "",
97 .hosttext = "",
98 .hostip = "",
99 .porttext = "",
100 .query = "",
101 .fragment = "",
102 .normalized = "file:///bin/bash",
103 .add_base_example = "file:///bin/bash",
104 .remove_base_example = "file:///bin/bash",
105 .path_elements =
106 {
107 "bin",
108 "bash",
109 },
110 },
111 {
112 .test = "http://www.example.com/name%20with%20spaces/",
113 .uri = "http://www.example.com/name%20with%20spaces/",
114 .uriescaped =
115 "http%3A%2F%2Fwww.example.com%2Fname%2520with%2520spaces%2F",
116 .scheme = "http",
117 .userinfo = "",
118 .hosttext = "www.example.com",
119 .hostip = "",
120 .porttext = "",
121 .query = "",
122 .fragment = "",
123 .normalized = "http://www.example.com/name%20with%20spaces/",
124 .add_base_example = "http://www.example.com/name%20with%20spaces/",
125 .remove_base_example = "name%20with%20spaces/",
126 .path_elements =
127 {
128 "name%20with%20spaces",
129 },
130 },
131 {
132 .test = "http://abcdefg@localhost/",
133 .uri = "http://abcdefg@localhost/",
134 .uriescaped = "http%3A%2F%2Fabcdefg%40localhost%2F",
135 .scheme = "http",
136 .userinfo = "abcdefg",
137 .hosttext = "localhost",
138 .hostip = "",
139 .porttext = "",
140 .query = "",
141 .fragment = "",
142 .normalized = "http://abcdefg@localhost/",
143 .add_base_example = "http://abcdefg@localhost/",
144 .remove_base_example = "//abcdefg@localhost/",
145 },
146 {
147 .test = "https://localhost:123/",
148 .uri = "https://localhost:123/",
149 .uriescaped = "https%3A%2F%2Flocalhost%3A123%2F",
150 .scheme = "https",
151 .userinfo = "",
152 .hosttext = "localhost",
153 .hostip = "",
154 .porttext = "123",
155 .query = "",
156 .fragment = "",
157 .normalized = "https://localhost:123/",
158 .add_base_example = "https://localhost:123/",
159 .remove_base_example = "https://localhost:123/",
160 },
161 {
162 .test = "http://[::1]/",
163 .uri = "http://[0000:0000:0000:0000:0000:0000:0000:0001]/",
164 .uriescaped = "http%3A%2F%2F%5B0000%3A0000%3A0000%3A0000%3A0000%3A0000%"
165 "3A0000%3A0001%5D%2F",
166 .scheme = "http",
167 .userinfo = "",
168 .hosttext = "::1",
169 .hostip = "::1",
170 .porttext = "",
171 .query = "",
172 .fragment = "",
173 .normalized = "http://[0000:0000:0000:0000:0000:0000:0000:0001]/",
174 .add_base_example = "http://[0000:0000:0000:0000:0000:0000:0000:0001]/",
175 .remove_base_example = "//[0000:0000:0000:0000:0000:0000:0000:0001]/",
176 },
177 {
178 .test = "http://a/b/c/d;p?q",
179 .uri = "http://a/b/c/d;p?q",
180 .uriescaped = "http%3A%2F%2Fa%2Fb%2Fc%2Fd%3Bp%3Fq",
181 .scheme = "http",
182 .userinfo = "",
183 .hosttext = "a",
184 .hostip = "",
185 .porttext = "",
186 .query = "q",
187 .fragment = "",
188 .normalized = "http://a/b/c/d;p?q",
189 .add_base_example = "http://a/b/c/d;p?q",
190 .remove_base_example = "//a/b/c/d;p?q",
191 .path_elements = {"b", "c", "d;p"},
192 .query_elements = {{"q", ""}},
193 },
194 {.test = "http://a/b/c/../d;p?q",
195 .uri = "http://a/b/c/../d;p?q",
196 .uriescaped = "http%3A%2F%2Fa%2Fb%2Fc%2F..%2Fd%3Bp%3Fq",
197 .scheme = "http",
198 .userinfo = "",
199 .hosttext = "a",
200 .hostip = "",
201 .porttext = "",
202 .query = "q",
203 .fragment = "",
204 .normalized = "http://a/b/d;p?q",
205 .add_base_example = "http://a/b/d;p?q",
206 .remove_base_example = "//a/b/c/../d;p?q",
207 .path_elements = {"b", "c", "..", "d;p"},
208 .query_elements = {{"q", ""}}},
209 {
210 .test = "http://example.com/abc/def/",
211 .uri = "http://example.com/abc/def/",
212 .uriescaped = "http%3A%2F%2Fexample.com%2Fabc%2Fdef%2F",
213 .scheme = "http",
214 .userinfo = "",
215 .hosttext = "example.com",
216 .hostip = "",
217 .porttext = "",
218 .query = "",
219 .fragment = "",
220 .normalized = "http://example.com/abc/def/",
221 .add_base_example = "http://example.com/abc/def/",
222 .remove_base_example = "//example.com/abc/def/",
223 .path_elements =
224 {
225 "abc",
226 "def",
227 },
228 },
229 {.test = "http://example.com/?abc",
230 .uri = "http://example.com/?abc",
231 .uriescaped = "http%3A%2F%2Fexample.com%2F%3Fabc",
232 .scheme = "http",
233 .userinfo = "",
234 .hosttext = "example.com",
235 .hostip = "",
236 .porttext = "",
237 .query = "abc",
238 .fragment = "",
239 .normalized = "http://example.com/?abc",
240 .add_base_example = "http://example.com/?abc",
241 .remove_base_example = "//example.com/?abc",
242 .query_elements = {{"abc", ""}}},
243 {
244 .test = "http://[vA.123456]/",
245 .uri = "http://[vA.123456]/",
246 .uriescaped = "http%3A%2F%2F%5BvA.123456%5D%2F",
247 .scheme = "http",
248 .userinfo = "",
249 .hosttext = "vA.123456",
250 .hostip = "",
251 .porttext = "",
252 .query = "",
253 .fragment = "",
254 .normalized = "http://[va.123456]/",
255 .add_base_example = "http://[vA.123456]/",
256 .remove_base_example = "//[vA.123456]/",
257 },
258 {
259 .test = "http://8.8.8.8/",
260 .uri = "http://8.8.8.8/",
261 .uriescaped = "http%3A%2F%2F8.8.8.8%2F",
262 .scheme = "http",
263 .userinfo = "",
264 .hosttext = "8.8.8.8",
265 .hostip = "8.8.8.8",
266 .porttext = "",
267 .query = "",
268 .fragment = "",
269 .normalized = "http://8.8.8.8/",
270 .add_base_example = "http://8.8.8.8/",
271 .remove_base_example = "//8.8.8.8/",
272 },
273 {.test = "http://www.example.com/?abc",
274 .uri = "http://www.example.com/?abc",
275 .uriescaped = "http%3A%2F%2Fwww.example.com%2F%3Fabc",
276 .scheme = "http",
277 .userinfo = "",
278 .hosttext = "www.example.com",
279 .hostip = "",
280 .porttext = "",
281 .query = "abc",
282 .fragment = "",
283 .normalized = "http://www.example.com/?abc",
284 .add_base_example = "http://www.example.com/?abc",
285 .remove_base_example = "./?abc",
286 .query_elements = {{"abc", ""}}},
287 {.test = "https://google.com?q=asd&x=y&zxc=asd",
288 .uri = "https://google.com?q=asd&x=y&zxc=asd",
289 .uriescaped = "https%3A%2F%2Fgoogle.com%3Fq%3Dasd%26x%3Dy%26zxc%3Dasd",
290 .scheme = "https",
291 .userinfo = "",
292 .hosttext = "google.com",
293 .hostip = "",
294 .porttext = "",
295 .query = "q=asd&x=y&zxc=asd",
296 .fragment = "",
297 .normalized = "https://google.com?q=asd&x=y&zxc=asd",
298 .add_base_example = "https://google.com?q=asd&x=y&zxc=asd",
299 .remove_base_example = "https://google.com?q=asd&x=y&zxc=asd",
300 .query_elements = {{"q", "asd"}, {"x", "y"}, {"zxc", "asd"}}},
301 {.test = "https://google.com?q=asd#newplace",
302 .uri = "https://google.com?q=asd#newplace",
303 .uriescaped = "https%3A%2F%2Fgoogle.com%3Fq%3Dasd%23newplace",
304 .scheme = "https",
305 .userinfo = "",
306 .hosttext = "google.com",
307 .hostip = "",
308 .porttext = "",
309 .query = "q=asd",
310 .fragment = "newplace",
311 .normalized = "https://google.com?q=asd#newplace",
312 .add_base_example = "https://google.com?q=asd#newplace",
313 .remove_base_example = "https://google.com?q=asd#newplace",
314 .query_elements = {{"q", "asd"}}},
315 };
316
317 class UriParserBase : public testing::Test {
318 protected:
319 void SetUp() override;
320 std::unique_ptr<UriparserSapiSandbox> sandbox_;
321 };
322
323 class UriParserTestData : public UriParserBase,
324 public testing::WithParamInterface<TestVariant> {};
325
SetUp()326 void UriParserBase::SetUp() {
327 sandbox_ = std::make_unique<UriparserSapiSandbox>();
328 ASSERT_THAT(sandbox_->Init(), IsOk());
329 }
330
TEST_P(UriParserTestData,TestUri)331 TEST_P(UriParserTestData, TestUri) {
332 const TestVariant& tv = GetParam();
333
334 UriParser uri(sandbox_.get(), tv.test);
335 ASSERT_THAT(uri.GetStatus(), IsOk());
336
337 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetUri());
338 ASSERT_EQ(ret, tv.uri);
339 }
340
TEST_P(UriParserTestData,TestUriEscaped)341 TEST_P(UriParserTestData, TestUriEscaped) {
342 const TestVariant& tv = GetParam();
343
344 UriParser uri(sandbox_.get(), tv.test);
345 ASSERT_THAT(uri.GetStatus(), IsOk());
346
347 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetUriEscaped(true, true));
348 ASSERT_EQ(ret, tv.uriescaped);
349 }
350
TEST_P(UriParserTestData,TestScheme)351 TEST_P(UriParserTestData, TestScheme) {
352 const TestVariant& tv = GetParam();
353
354 UriParser uri(sandbox_.get(), tv.test);
355 ASSERT_THAT(uri.GetStatus(), IsOk());
356
357 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetScheme());
358 ASSERT_EQ(ret, tv.scheme);
359 }
360
TEST_P(UriParserTestData,TestUserInfo)361 TEST_P(UriParserTestData, TestUserInfo) {
362 const TestVariant& tv = GetParam();
363
364 UriParser uri(sandbox_.get(), tv.test);
365 ASSERT_THAT(uri.GetStatus(), IsOk());
366
367 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetUserInfo());
368 ASSERT_EQ(ret, tv.userinfo);
369 }
370
TEST_P(UriParserTestData,TestHostText)371 TEST_P(UriParserTestData, TestHostText) {
372 const TestVariant& tv = GetParam();
373
374 UriParser uri(sandbox_.get(), tv.test);
375 ASSERT_THAT(uri.GetStatus(), IsOk());
376
377 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetHostText());
378 ASSERT_EQ(ret, tv.hosttext);
379 }
380
TEST_P(UriParserTestData,TestHostIP)381 TEST_P(UriParserTestData, TestHostIP) {
382 const TestVariant& tv = GetParam();
383
384 UriParser uri(sandbox_.get(), tv.test);
385 ASSERT_THAT(uri.GetStatus(), IsOk());
386
387 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetHostIP());
388 ASSERT_EQ(ret, tv.hostip);
389 }
390
TEST_P(UriParserTestData,TestPortText)391 TEST_P(UriParserTestData, TestPortText) {
392 const TestVariant& tv = GetParam();
393
394 UriParser uri(sandbox_.get(), tv.test);
395 ASSERT_THAT(uri.GetStatus(), IsOk());
396
397 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetPortText());
398 ASSERT_EQ(ret, tv.porttext);
399 }
400
TEST_P(UriParserTestData,TestQuery)401 TEST_P(UriParserTestData, TestQuery) {
402 const TestVariant& tv = GetParam();
403
404 UriParser uri(sandbox_.get(), tv.test);
405 ASSERT_THAT(uri.GetStatus(), IsOk());
406
407 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetQuery());
408 ASSERT_EQ(ret, tv.query);
409 }
410
TEST_P(UriParserTestData,TestFragment)411 TEST_P(UriParserTestData, TestFragment) {
412 const TestVariant& tv = GetParam();
413
414 UriParser uri(sandbox_.get(), tv.test);
415 ASSERT_THAT(uri.GetStatus(), IsOk());
416
417 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetFragment());
418 ASSERT_EQ(ret, tv.fragment);
419 }
420
TEST_P(UriParserTestData,TestNormalize)421 TEST_P(UriParserTestData, TestNormalize) {
422 const TestVariant& tv = GetParam();
423
424 UriParser uri(sandbox_.get(), tv.test);
425 ASSERT_THAT(uri.GetStatus(), IsOk());
426
427 ASSERT_THAT(uri.NormalizeSyntax(), IsOk());
428 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret, uri.GetUri());
429 ASSERT_EQ(ret, tv.normalized);
430 }
431
TEST_P(UriParserTestData,TestMultiple)432 TEST_P(UriParserTestData, TestMultiple) {
433 const TestVariant& tv = GetParam();
434
435 UriParser uri(sandbox_.get(), tv.test);
436 ASSERT_THAT(uri.GetStatus(), IsOk());
437
438 std::string ret;
439 SAPI_ASSERT_OK_AND_ASSIGN(ret, uri.GetQuery());
440 ASSERT_EQ(ret, tv.query);
441
442 SAPI_ASSERT_OK_AND_ASSIGN(ret, uri.GetHostIP());
443 ASSERT_EQ(ret, tv.hostip);
444
445 ASSERT_THAT(uri.NormalizeSyntax(), IsOk());
446 SAPI_ASSERT_OK_AND_ASSIGN(ret, uri.GetUri());
447 ASSERT_EQ(ret, tv.normalized);
448 }
449
TEST_P(UriParserTestData,TestAddBaseExample)450 TEST_P(UriParserTestData, TestAddBaseExample) {
451 const TestVariant& tv = GetParam();
452
453 UriParser uri(sandbox_.get(), tv.test);
454 ASSERT_THAT(uri.GetStatus(), IsOk());
455
456 SAPI_ASSERT_OK_AND_ASSIGN(std::string ret,
457 uri.GetUriWithBase("http://www.example.com"));
458 ASSERT_EQ(ret, tv.add_base_example);
459 }
460
TEST_P(UriParserTestData,TestRemoveBaseExample)461 TEST_P(UriParserTestData, TestRemoveBaseExample) {
462 const TestVariant& tv = GetParam();
463
464 UriParser uri(sandbox_.get(), tv.test);
465 ASSERT_THAT(uri.GetStatus(), IsOk());
466
467 SAPI_ASSERT_OK_AND_ASSIGN(
468 std::string ret, uri.GetUriWithoutBase("http://www.example.com", false));
469 ASSERT_EQ(ret, tv.remove_base_example);
470 }
471
TEST_P(UriParserTestData,TestPath)472 TEST_P(UriParserTestData, TestPath) {
473 const TestVariant& tv = GetParam();
474
475 UriParser uri(sandbox_.get(), tv.test);
476 ASSERT_THAT(uri.GetStatus(), IsOk());
477
478 SAPI_ASSERT_OK_AND_ASSIGN(std::vector<std::string> ret, uri.GetPath());
479 ASSERT_EQ(ret.size(), tv.path_elements.size());
480 for (int i = 0; i < ret.size(); ++i) {
481 ASSERT_EQ(ret[i], tv.path_elements[i]);
482 }
483 }
484
TEST_P(UriParserTestData,TestQueryElements)485 TEST_P(UriParserTestData, TestQueryElements) {
486 const TestVariant& tv = GetParam();
487
488 UriParser uri(sandbox_.get(), tv.test);
489 ASSERT_THAT(uri.GetStatus(), IsOk());
490
491 SAPI_ASSERT_OK_AND_ASSIGN(auto ret, uri.GetQueryElements());
492 ASSERT_EQ(ret.size(), tv.query_elements.size());
493 for (auto orig : tv.query_elements) {
494 ASSERT_NE(ret.find(orig.first), ret.end());
495 ASSERT_EQ(ret[orig.first], orig.second);
496 }
497 }
498
499 INSTANTIATE_TEST_SUITE_P(UriParserBase, UriParserTestData,
500 testing::ValuesIn(TestData));
501
502 } // namespace
503