TestURLPatternGlue.cpp (32116B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "gtest/gtest.h" 7 #include "gtest/MozGTestBench.h" // For MOZ_GTEST_BENCH 8 #include "mozilla/net/URLPatternGlue.h" 9 #include "mozilla/net/urlpattern_glue.h" 10 11 using namespace mozilla::net; 12 13 template <typename T> 14 using Optional = mozilla::Maybe<T>; 15 16 // pattern construction from string 17 TEST(TestURLPatternGlue, PatternFromString) 18 { 19 nsCString str(":café://:foo"); 20 UrlpPattern pattern{}; 21 UrlpOptions options = {.ignore_case = false}; 22 bool res = urlp_parse_pattern_from_string(&str, nullptr, options, &pattern); 23 ASSERT_TRUE(res); 24 ASSERT_TRUE(pattern._0); 25 } 26 27 TEST(TestURLPatternGlue, PatternFromStringOnlyPathname) 28 { 29 nsCString str("/foo/thing"); 30 UrlpPattern pattern{}; 31 UrlpOptions options = {.ignore_case = false}; 32 bool res = urlp_parse_pattern_from_string(&str, nullptr, options, &pattern); 33 ASSERT_FALSE(res); 34 ASSERT_FALSE(pattern._0); 35 } 36 37 bool operator==(const UrlpInnerMatcher& a, const UrlpInnerMatcher& b) { 38 if (a.inner_type != b.inner_type) { 39 return false; 40 } 41 42 switch (a.inner_type) { 43 case UrlpInnerMatcherType::Literal: { 44 return a.literal.Equals(b.literal); 45 } 46 case UrlpInnerMatcherType::SingleCapture: { 47 if (a.allow_empty == b.allow_empty && 48 a.filter_exists == b.filter_exists) { 49 if (a.filter_exists) { 50 return a.filter == b.filter; 51 } 52 return true; 53 } 54 return false; 55 } 56 case UrlpInnerMatcherType::RegExp: { 57 return a.regexp.Equals(b.regexp); 58 } 59 default: { 60 return false; 61 } 62 } 63 } 64 65 bool operator==(const UrlpMatcher& a, const UrlpMatcher& b) { 66 return a.prefix.Equals(b.prefix) && a.suffix.Equals(b.suffix) && 67 a.inner == b.inner; 68 } 69 70 UrlpInit CreateInit(const nsCString& protocol, const nsCString& username, 71 const nsCString& password, const nsCString& hostname, 72 const nsCString& port, const nsCString& pathname, 73 const nsCString& search, const nsCString& hash, 74 const nsCString& baseUrl) { 75 return UrlpInit{ 76 .protocol = CreateMaybeString(protocol, !protocol.IsEmpty()), 77 .username = CreateMaybeString(username, !username.IsEmpty()), 78 .password = CreateMaybeString(password, !password.IsEmpty()), 79 .hostname = CreateMaybeString(hostname, !hostname.IsEmpty()), 80 .port = CreateMaybeString(port, !port.IsEmpty()), 81 .pathname = CreateMaybeString(pathname, !pathname.IsEmpty()), 82 .search = CreateMaybeString(search, !search.IsEmpty()), 83 .hash = CreateMaybeString(hash, !hash.IsEmpty()), 84 .base_url = CreateMaybeString(baseUrl, !baseUrl.IsEmpty()), 85 }; 86 } 87 88 UrlpInit CreateSimpleInit(const nsCString& protocol, const nsCString& hostname, 89 const nsCString& pathname) { 90 return CreateInit(protocol, ""_ns, ""_ns, hostname, ""_ns, pathname, ""_ns, 91 ""_ns, ""_ns); 92 } 93 94 UrlpInit CreateInit(const char* protocol, const char* username, 95 const char* password, const char* hostname, 96 const char* port, const char* pathname, const char* search, 97 const char* hash, const char* base = "") { 98 return CreateInit(nsCString(protocol), nsCString(username), 99 nsCString(password), nsCString(hostname), nsCString(port), 100 nsCString(pathname), nsCString(search), nsCString(hash), 101 nsCString(base)); 102 } 103 104 // pattern construction from init 105 TEST(TestURLPatternGlue, PatternFromInit) 106 { 107 UrlpPattern pattern{}; 108 UrlpOptions options = {.ignore_case = false}; 109 UrlpInit init = CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns); 110 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 111 ASSERT_TRUE(res); 112 ASSERT_TRUE(pattern._0); 113 114 auto proto = UrlpGetProtocol(pattern); 115 ASSERT_EQ(proto, "https"_ns); 116 } 117 118 TEST(TestURLPatternGlue, PatternFromInitOnlyPathname) 119 { 120 UrlpPattern pattern{}; 121 UrlpOptions options = {.ignore_case = false}; 122 UrlpInit init = CreateSimpleInit(""_ns, ""_ns, "/foo/thing"_ns); 123 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 124 ASSERT_TRUE(res); 125 ASSERT_TRUE(pattern._0); 126 127 auto proto = UrlpGetProtocol(pattern); 128 ASSERT_EQ(proto, nsCString("*")); 129 auto host = UrlpGetHostname(pattern); 130 ASSERT_EQ(host, nsCString("*")); 131 auto path = UrlpGetPathname(pattern); 132 ASSERT_EQ(path, nsCString("/foo/thing")); 133 134 Optional<nsAutoCString> execBaseUrl; // None 135 UrlpInput input = CreateUrlpInput(init); 136 Optional<UrlpResult> r = UrlpPatternExec(pattern, input, execBaseUrl); 137 ASSERT_TRUE(r.isSome()); 138 ASSERT_TRUE(r->mProtocol.isSome()); 139 ASSERT_EQ(r->mProtocol.value().mInput, nsCString("")); 140 ASSERT_TRUE(r->mPathname.isSome()); 141 ASSERT_EQ(r->mPathname.value().mInput, "/foo/thing"_ns); 142 } 143 144 // pattern getters 145 TEST(TestURLPatternGlue, UrlPatternGetters) 146 { 147 UrlpPattern pattern{}; 148 UrlpOptions options = {.ignore_case = false}; 149 150 UrlpInit init = 151 CreateInit("https"_ns, "user"_ns, "passw"_ns, "example.com"_ns, "66"_ns, 152 "/"_ns, "find"_ns, "anchor"_ns, ""_ns); 153 bool rv = urlp_parse_pattern_from_init(&init, options, &pattern); 154 ASSERT_TRUE(rv); 155 ASSERT_TRUE(pattern._0); 156 157 nsAutoCString res; 158 res = UrlpGetProtocol(pattern); 159 ASSERT_EQ(res, nsCString("https")); 160 res = UrlpGetUsername(pattern); 161 ASSERT_EQ(res, nsCString("user")); 162 res = UrlpGetPassword(pattern); 163 ASSERT_EQ(res, nsCString("passw")); 164 res = UrlpGetHostname(pattern); 165 ASSERT_EQ(res, nsCString("example.com")); 166 res = UrlpGetPort(pattern); 167 ASSERT_EQ(res, nsCString("66")); 168 res = UrlpGetPathname(pattern); 169 ASSERT_EQ(res, nsCString("/")); 170 res = UrlpGetSearch(pattern); 171 ASSERT_EQ(res, nsCString("find")); 172 res = UrlpGetHash(pattern); 173 ASSERT_EQ(res, nsCString("anchor")); 174 // neither lib or quirks URLPattern has base_url so nothing to check 175 } 176 177 // UrlPattern.test() from_init 178 TEST(TestURLPatternGlue, UrlPatternTestInit) 179 { 180 // check basic literal matching (minimal fields) 181 { 182 UrlpPattern pattern{}; 183 UrlpOptions options = {.ignore_case = false}; 184 UrlpInit init = CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns); 185 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 186 ASSERT_TRUE(res); 187 188 Optional<nsCString> base; 189 { // path not fixed up (?) 190 auto test = CreateUrlpInput( 191 CreateSimpleInit("https"_ns, "example.com"_ns, ""_ns)); 192 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 193 } 194 { 195 auto test = CreateUrlpInput( 196 CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns)); 197 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 198 } 199 { // unspecified user and password is fine 200 auto test = CreateUrlpInput( 201 CreateInit("https", "user", "pass", "example.com", "", "/", "", "")); 202 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 203 } 204 { // unspecified port is fine 205 auto test = CreateUrlpInput( 206 CreateInit("https", "", "", "example.com", "444", "/", "", "")); 207 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 208 } 209 { // unspecified search is fine 210 auto test = CreateUrlpInput( 211 CreateInit("https", "", "", "example.com", "", "/", "thisok", "")); 212 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 213 } 214 { // unspecified hash is fine 215 auto test = CreateUrlpInput( 216 CreateInit("https", "", "", "example.com", "", "/", "", "thisok")); 217 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 218 } 219 { // pathname different 220 auto test = CreateUrlpInput( 221 CreateSimpleInit("https"_ns, "example.com"_ns, "/a"_ns)); 222 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 223 } 224 { // scheme different 225 auto test = CreateUrlpInput( 226 CreateSimpleInit("http"_ns, "example.com"_ns, "/"_ns)); 227 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 228 } 229 { // domain different 230 auto test = CreateUrlpInput( 231 CreateSimpleInit("https"_ns, "example.org"_ns, "/"_ns)); 232 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 233 } 234 } 235 236 // check basic literal matching 237 { 238 UrlpPattern pattern{}; 239 UrlpOptions options = {.ignore_case = false}; 240 auto init = 241 CreateInit("https"_ns, "user"_ns, "anything"_ns, "example.com"_ns, 242 "444"_ns, "/"_ns, "query"_ns, "frag"_ns, ""_ns); 243 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 244 ASSERT_TRUE(res); 245 246 nsCString anything("anything"); 247 Optional<nsCString> base; 248 { // exact match 249 auto test = CreateUrlpInput(init); 250 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 251 } 252 { // missing protocol 253 auto test = 254 CreateUrlpInput(CreateInit("", "user", anything.get(), "example.com", 255 "444", "/", "query", "frag")); 256 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 257 } 258 { // missing user 259 auto test = 260 CreateUrlpInput(CreateInit("https", "", anything.get(), "example.com", 261 "444", "/", "query", "frag")); 262 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 263 } 264 { // missing password 265 auto test = CreateUrlpInput(CreateInit("https", "user", "", "example.com", 266 "444", "/", "query", "frag")); 267 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 268 } 269 { // missing hostname 270 auto test = CreateUrlpInput(CreateInit("https", "user", anything.get(), 271 "", "444", "/", "query", "frag")); 272 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 273 } 274 { // missing port 275 auto test = 276 CreateUrlpInput(CreateInit("https", "user", anything.get(), 277 "example.com", "", "/", "query", "frag")); 278 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 279 } 280 { // missing query 281 auto test = 282 CreateUrlpInput(CreateInit("https", "user", anything.get(), 283 "example.com", "444", "/", "", "frag")); 284 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 285 } 286 { // missing frag 287 auto test = 288 CreateUrlpInput(CreateInit("https", "user", anything.get(), 289 "example.com", "444", "/", "query", "")); 290 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 291 } 292 } 293 294 // check basic url with wildcard 295 { 296 UrlpPattern pattern{}; 297 UrlpOptions options = {.ignore_case = false}; 298 auto init = CreateSimpleInit("https"_ns, "example.com"_ns, "/*"_ns); 299 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 300 ASSERT_TRUE(res); 301 302 Optional<nsCString> base; 303 { // root path matches wildcard 304 auto test = CreateUrlpInput( 305 CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns)); 306 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 307 } 308 { // filename matches wildcard 309 auto test = CreateUrlpInput( 310 CreateSimpleInit("https"_ns, "example.com"_ns, "/thing"_ns)); 311 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 312 } 313 { // dir/filename matches wildcard 314 auto test = CreateUrlpInput( 315 CreateSimpleInit("https"_ns, "example.com"_ns, "/dir/thing"_ns)); 316 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 317 } 318 } 319 320 // check matching in pathname (needs to be at least two slashes) 321 { 322 UrlpPattern pattern{}; 323 UrlpOptions options = {.ignore_case = false}; 324 auto init = 325 CreateSimpleInit("https"_ns, "example.com"_ns, "/:category/*"_ns); 326 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 327 ASSERT_TRUE(res); 328 329 Optional<nsCString> base; 330 { // no directory and not enough slashes 331 auto test = CreateUrlpInput( 332 CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns)); 333 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 334 } 335 { // no directory 336 auto test = CreateUrlpInput( 337 CreateSimpleInit("https"_ns, "example.com"_ns, "//"_ns)); 338 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 339 } 340 { // not enough slashes 341 auto test = CreateUrlpInput( 342 CreateSimpleInit("https"_ns, "example.com"_ns, "/products"_ns)); 343 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 344 } 345 { // dir/ works 346 auto test = CreateUrlpInput( 347 CreateSimpleInit("https"_ns, "example.com"_ns, "/products/"_ns)); 348 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 349 } 350 { // diretory/filename 351 auto test = CreateUrlpInput( 352 CreateSimpleInit("https"_ns, "example.com"_ns, "/blog/thing"_ns)); 353 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 354 } 355 { // nested directory 356 auto test = CreateUrlpInput( 357 CreateSimpleInit("https"_ns, "example.com"_ns, "/blog/thing/"_ns)); 358 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 359 } 360 } 361 362 // check optional `s` in protocol 363 { 364 UrlpPattern pattern{}; 365 UrlpOptions options = {.ignore_case = false}; 366 auto init = CreateSimpleInit("http{s}?"_ns, "example.com"_ns, "/"_ns); 367 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 368 ASSERT_TRUE(res); 369 370 Optional<nsCString> base; 371 { // insecure matches 372 auto test = CreateUrlpInput( 373 CreateSimpleInit("http"_ns, "example.com"_ns, "/"_ns)); 374 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 375 } 376 { // secure matches 377 auto test = CreateUrlpInput( 378 CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns)); 379 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 380 } 381 } 382 383 // basic relative wildcard path with base domain 384 { 385 UrlpPattern pattern{}; 386 UrlpOptions options = {.ignore_case = false}; 387 auto init = CreateInit(""_ns, ""_ns, ""_ns, ""_ns, ""_ns, "/admin/*"_ns, 388 ""_ns, ""_ns, "https://example.com"_ns); 389 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 390 ASSERT_TRUE(res); 391 392 Optional<nsCString> base; 393 { 394 auto test = CreateUrlpInput( 395 CreateSimpleInit("https"_ns, "example.com"_ns, "/admin/"_ns)); 396 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 397 } 398 { 399 auto test = CreateUrlpInput( 400 CreateSimpleInit("https"_ns, "example.com"_ns, "/admin/thing"_ns)); 401 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 402 } 403 { // incorrect relative path doesn't match 404 // 405 auto test = CreateUrlpInput( 406 CreateSimpleInit("https"_ns, "example.com"_ns, "/nonadmin/"_ns)); 407 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 408 } 409 { // root path not matching relative path doesn't match 410 auto test = CreateUrlpInput( 411 CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns)); 412 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 413 } 414 } 415 } 416 417 // UrlPattern.test() from_string 418 TEST(TestURLPatternGlue, UrlPatternTestString) 419 { 420 // check basic literal matching (minimal fields) 421 { 422 nsCString str("https://example.com/"); 423 UrlpPattern pattern{}; 424 UrlpOptions options = {.ignore_case = false}; 425 bool res = urlp_parse_pattern_from_string(&str, nullptr, options, &pattern); 426 ASSERT_TRUE(res); 427 428 Optional<nsCString> base; 429 { // path fixed up "/" 430 auto test = CreateUrlpInput("https://example.com"_ns); 431 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 432 } 433 { 434 auto test = CreateUrlpInput("https://example.com/"_ns); 435 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 436 } 437 { // unspecified user and password is fine 438 auto test = CreateUrlpInput("https://user:passw@example.com"_ns); 439 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 440 } 441 { // unspecified port is empty so 444 doesn't match 442 auto test = CreateUrlpInput("https://example.com:444/"_ns); 443 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 444 } 445 { // unspecified search is fine 446 auto test = CreateUrlpInput("https://example.com/?thisok"_ns); 447 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 448 } 449 { // unspecified hash is fine 450 auto test = CreateUrlpInput("https://example.com/#thisok"_ns); 451 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 452 } 453 { // pathname different 454 auto test = CreateUrlpInput("https://example.com/a"_ns); 455 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 456 } 457 { // scheme different 458 auto test = CreateUrlpInput("http://example.com/"_ns); 459 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 460 } 461 { // domain different 462 auto test = CreateUrlpInput("http://example.org"_ns); 463 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 464 } 465 } 466 467 // check basic literal matching (all fields, except password) 468 // because user:pass is parsed as: `username: user:pass, password: *` 469 // when pattern is from_string 470 { 471 nsCString str("https://user:*@example.com:444/?query#frag"); 472 UrlpPattern pattern{}; 473 UrlpOptions options = {.ignore_case = false}; 474 nsCString baseUrl(""); 475 bool res = 476 urlp_parse_pattern_from_string(&str, &baseUrl, options, &pattern); 477 ASSERT_TRUE(res); 478 479 Optional<nsCString> base; 480 { // exact match, except password 481 auto test = CreateUrlpInput( 482 "https://user:anything@example.com:444/?query#frag"_ns); 483 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 484 } 485 { // missing protocol 486 auto test = 487 CreateUrlpInput("user:anything@example.com:444/?query#frag"_ns); 488 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 489 } 490 { // missing user 491 auto test = 492 CreateUrlpInput("https://:anything@example.com:444/?query#frag"_ns); 493 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 494 } 495 { // missing password is fine 496 auto test = 497 CreateUrlpInput("https://user@example.com:444/?query#frag"_ns); 498 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 499 } 500 { // missing password is fine 501 auto test = 502 CreateUrlpInput("https://user@example.com:444/?query#frag"_ns); 503 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 504 } 505 { // missing hostname 506 auto test = CreateUrlpInput("https://user:anything@:444/?query#frag"_ns); 507 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 508 } 509 { // missing port 510 auto test = 511 CreateUrlpInput("https://user:anything@example.com/?query#frag"_ns); 512 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 513 } 514 { // missing query 515 auto test = 516 CreateUrlpInput("https://user:anything@example.com:444/#frag"_ns); 517 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 518 } 519 { // missing frag 520 auto test = 521 CreateUrlpInput("https://user:anything@example.com:444/?query"_ns); 522 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 523 } 524 } 525 526 // check basic url with wildcard 527 { 528 nsCString str("https://example.com/*"); 529 UrlpPattern pattern{}; 530 UrlpOptions options = {.ignore_case = false}; 531 nsCString baseUrl(""); 532 bool res = 533 urlp_parse_pattern_from_string(&str, &baseUrl, options, &pattern); 534 ASSERT_TRUE(res); 535 536 Optional<nsCString> base; 537 { 538 auto test = CreateUrlpInput("https://example.com/"_ns); 539 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 540 } 541 { 542 auto test = CreateUrlpInput("https://example.com/thing"_ns); 543 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 544 } 545 { 546 auto test = CreateUrlpInput("https://example.com/dir/thing"_ns); 547 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 548 } 549 } 550 551 // check matching in pathname (needs to be at least two slashes) 552 { 553 nsCString str("https://example.com/:category/*"); 554 UrlpPattern pattern{}; 555 UrlpOptions options = {.ignore_case = false}; 556 nsCString baseUrl(""); 557 bool res = 558 urlp_parse_pattern_from_string(&str, &baseUrl, options, &pattern); 559 ASSERT_TRUE(res); 560 561 Optional<nsCString> base; 562 { 563 auto test = CreateUrlpInput("https://example.com/"_ns); 564 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 565 } 566 { // not enough slashes 567 auto test = CreateUrlpInput("https://example.com/products"_ns); 568 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 569 } 570 { 571 auto test = CreateUrlpInput("https://example.com/products/"_ns); 572 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 573 } 574 { 575 auto test = CreateUrlpInput("https://example.com/blog/thing"_ns); 576 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 577 } 578 { // 3 slashes 579 auto test = CreateUrlpInput("https://example.com/blog/thing/"_ns); 580 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 581 } 582 } 583 584 // check optional `s` in protocol 585 { 586 nsCString str("http{s}?://example.com/"); 587 UrlpPattern pattern{}; 588 UrlpOptions options = {.ignore_case = false}; 589 nsCString baseUrl(""); 590 bool res = 591 urlp_parse_pattern_from_string(&str, &baseUrl, options, &pattern); 592 ASSERT_TRUE(res); 593 594 Optional<nsCString> base; 595 { 596 auto test = CreateUrlpInput("http://example.com/"_ns); 597 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 598 } 599 { 600 auto test = CreateUrlpInput("https://example.com/"_ns); 601 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 602 } 603 } 604 605 // basic relative wildcard path with base domain 606 { 607 nsCString str("../admin/*"); 608 UrlpPattern pattern{}; 609 UrlpOptions options = {.ignore_case = false}; 610 nsCString baseUrl("https://example.com/forum"); 611 // MaybeString baseUrl {.string = "https://example.com/forum"_ns, .valid = 612 // true }; 613 bool res = 614 urlp_parse_pattern_from_string(&str, &baseUrl, options, &pattern); 615 ASSERT_TRUE(res); 616 617 Optional<nsCString> base; 618 { 619 auto test = CreateUrlpInput("https://example.com/admin/"_ns); 620 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 621 } 622 { 623 auto test = CreateUrlpInput("https://example.com/admin/thing"_ns); 624 ASSERT_TRUE(UrlpPatternTest(pattern, test, base)); 625 } 626 { 627 auto test = CreateUrlpInput("https://example.com/nonadmin/"_ns); 628 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 629 } 630 { 631 auto test = CreateUrlpInput("https://example.com/"_ns); 632 ASSERT_FALSE(UrlpPatternTest(pattern, test, base)); 633 } 634 } 635 } 636 637 TEST(TestURLPatternGlue, MatchInputFromString) 638 { 639 { 640 nsCString url("https://example.com/"); 641 UrlpMatchInputAndInputs matchInputAndInputs; 642 bool res = urlp_process_match_input_from_string(&url, nullptr, 643 &matchInputAndInputs); 644 ASSERT_TRUE(res); 645 ASSERT_EQ(matchInputAndInputs.input.protocol, "https"_ns); 646 ASSERT_EQ(matchInputAndInputs.input.hostname, "example.com"_ns); 647 ASSERT_EQ(matchInputAndInputs.input.pathname, "/"_ns); 648 ASSERT_EQ(matchInputAndInputs.input.username, ""); 649 ASSERT_EQ(matchInputAndInputs.input.password, ""); 650 ASSERT_EQ(matchInputAndInputs.input.port, ""); 651 ASSERT_EQ(matchInputAndInputs.input.search, ""); 652 ASSERT_EQ(matchInputAndInputs.input.hash, ""); 653 ASSERT_EQ(matchInputAndInputs.inputs.string_or_init_type, 654 UrlpStringOrInitType::String); 655 ASSERT_EQ(matchInputAndInputs.inputs.str, url); 656 ASSERT_EQ(matchInputAndInputs.inputs.base.valid, false); 657 } 658 { 659 nsCString expected("https://example.com/some/dir"); 660 nsCString base_url("https://example.com"); 661 nsCString relative_url("/some/dir"); 662 UrlpMatchInputAndInputs matchInputAndInputs; 663 bool res = urlp_process_match_input_from_string(&relative_url, &base_url, 664 &matchInputAndInputs); 665 ASSERT_TRUE(res); 666 ASSERT_EQ(matchInputAndInputs.input.protocol, "https"_ns); 667 ASSERT_EQ(matchInputAndInputs.input.hostname, "example.com"_ns); 668 ASSERT_EQ(matchInputAndInputs.input.pathname, "/some/dir"_ns); 669 ASSERT_EQ(matchInputAndInputs.input.username, ""); 670 ASSERT_EQ(matchInputAndInputs.input.password, ""); 671 ASSERT_EQ(matchInputAndInputs.input.port, ""); 672 ASSERT_EQ(matchInputAndInputs.input.search, ""); 673 ASSERT_EQ(matchInputAndInputs.input.hash, ""); 674 ASSERT_EQ(matchInputAndInputs.inputs.string_or_init_type, 675 UrlpStringOrInitType::String); 676 ASSERT_EQ(matchInputAndInputs.inputs.str, relative_url); 677 ASSERT_EQ(matchInputAndInputs.inputs.base.string, base_url); 678 } 679 } 680 681 void assert_maybe_string_same(const MaybeString& s1, const MaybeString& s2) { 682 ASSERT_EQ(s1.valid, s2.valid); 683 if (s1.valid) { 684 ASSERT_EQ(s1.string, s2.string); 685 } 686 } 687 688 void assert_inits_same(const UrlpInit& i1, const UrlpInit& i2) { 689 assert_maybe_string_same(i1.protocol, i2.protocol); 690 assert_maybe_string_same(i1.username, i2.username); 691 assert_maybe_string_same(i1.password, i2.password); 692 assert_maybe_string_same(i1.hostname, i2.hostname); 693 assert_maybe_string_same(i1.port, i2.port); 694 assert_maybe_string_same(i1.pathname, i2.pathname); 695 assert_maybe_string_same(i1.search, i2.search); 696 assert_maybe_string_same(i1.hash, i2.hash); 697 assert_maybe_string_same(i1.base_url, i2.base_url); 698 } 699 700 void assert_match_inputs_same(const UrlpMatchInput& input, 701 const UrlpMatchInput& expected) { 702 ASSERT_EQ(input.protocol, expected.protocol); 703 ASSERT_EQ(input.hostname, expected.hostname); 704 ASSERT_EQ(input.pathname, expected.pathname); 705 ASSERT_EQ(input.username, expected.username); 706 ASSERT_EQ(input.password, expected.password); 707 ASSERT_EQ(input.port, expected.port); 708 ASSERT_EQ(input.search, expected.search); 709 ASSERT_EQ(input.hash, expected.hash); 710 } 711 712 UrlpMatchInput createMatchInputHelper(const nsCString& proto, 713 const nsCString& host, 714 const nsCString& path) { 715 return { 716 .protocol = proto, 717 .username = ""_ns, 718 .password = ""_ns, 719 .hostname = host, 720 .port = ""_ns, 721 .pathname = path, 722 .search = ""_ns, 723 .hash = ""_ns, 724 }; 725 } 726 727 TEST(TestURLPatternGlue, MatchInputFromInit) 728 { 729 { // no base init 730 UrlpMatchInputAndInputs matchInputAndInputs; 731 auto init = CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns); 732 auto expected = CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns); 733 bool res = urlp_process_match_input_from_init(&init, nullptr, 734 &matchInputAndInputs); 735 ASSERT_TRUE(res); 736 737 UrlpMatchInput expected_match_input = 738 createMatchInputHelper("https"_ns, "example.com"_ns, "/"_ns); 739 assert_match_inputs_same(matchInputAndInputs.input, expected_match_input); 740 ASSERT_EQ(matchInputAndInputs.inputs.string_or_init_type, 741 UrlpStringOrInitType::Init); 742 assert_inits_same(matchInputAndInputs.inputs.init, init); 743 ASSERT_EQ(matchInputAndInputs.inputs.str, ""_ns); 744 ASSERT_EQ(matchInputAndInputs.inputs.base.valid, false); 745 } 746 { // base + relative url produces expected match input 747 nsCString expected_base_url("https://example.com"); 748 749 auto init = CreateInit("", "", "", "", "", "/some/dir", "", "", 750 "https://example.com"); 751 UrlpMatchInputAndInputs matchInputAndInputs; 752 bool res = urlp_process_match_input_from_init(&init, nullptr, 753 &matchInputAndInputs); 754 ASSERT_TRUE(res); 755 756 UrlpMatchInput expected_match_input = 757 createMatchInputHelper("https"_ns, "example.com"_ns, "/some/dir"_ns); 758 assert_match_inputs_same(matchInputAndInputs.input, expected_match_input); 759 ASSERT_EQ(matchInputAndInputs.inputs.string_or_init_type, 760 UrlpStringOrInitType::Init); 761 assert_inits_same(matchInputAndInputs.inputs.init, init); 762 ASSERT_EQ(matchInputAndInputs.inputs.str, ""_ns); 763 ASSERT_EQ(matchInputAndInputs.inputs.base.valid, false); 764 } 765 } 766 767 void assert_matcher_same(UrlpMatcher& componentMatcher, UrlpMatcher& expected) { 768 ASSERT_EQ(componentMatcher.prefix, expected.prefix); 769 ASSERT_EQ(componentMatcher.suffix, expected.suffix); 770 ASSERT_EQ(componentMatcher.inner.inner_type, expected.inner.inner_type); 771 ASSERT_EQ(componentMatcher.inner.literal, expected.inner.literal); 772 ASSERT_EQ(componentMatcher.inner.allow_empty, expected.inner.allow_empty); 773 ASSERT_EQ(componentMatcher.inner.filter_exists, expected.inner.filter_exists); 774 ASSERT_EQ(componentMatcher.inner.filter, expected.inner.filter); 775 ASSERT_EQ(componentMatcher.inner.regexp, expected.inner.regexp); 776 ASSERT_TRUE(componentMatcher == expected); 777 } 778 779 TEST(TestURLPatternGlue, UrlPatternGetComponentBasic) 780 { 781 nsCString str("http://:foo"); 782 UrlpOptions options = {.ignore_case = false}; 783 UrlpPattern pattern{}; 784 bool res = urlp_parse_pattern_from_string(&str, nullptr, options, &pattern); 785 ASSERT_TRUE(res); 786 ASSERT_TRUE(pattern._0); 787 788 UrlpInnerMatcher expectedInnerMatcher = { 789 .inner_type = UrlpInnerMatcherType::Literal, 790 .literal = "http"_ns, 791 .allow_empty = false, 792 .filter_exists = false, 793 .filter = 'x', 794 .regexp = ""_ns, 795 }; 796 UrlpMatcher expectedMatcher = { 797 .prefix = ""_ns, 798 .suffix = ""_ns, 799 .inner = expectedInnerMatcher, 800 }; 801 nsCString expectedPatternString("http"); 802 nsCString expectedRegexp("^http$"); 803 804 UrlpComponent componentProtocol{}; 805 auto protoStr = UrlpGetProtocol(pattern); 806 ASSERT_EQ(protoStr, expectedPatternString); 807 808 auto hostnameStr = UrlpGetHostname(pattern); 809 nsCString expectedHostnamePatternString(":foo"); 810 nsCString expectedHostnameRegexp("^([^\\.]+?)$"); 811 expectedMatcher.inner.inner_type = UrlpInnerMatcherType::SingleCapture; 812 expectedMatcher.inner.literal = ""_ns; 813 expectedMatcher.inner.filter_exists = true; 814 expectedMatcher.inner.filter = '.'; 815 ASSERT_EQ(hostnameStr, expectedHostnamePatternString); 816 817 auto pathnameStr = UrlpGetPathname(pattern); 818 nsCString expectedPathnamePatternString("*"); 819 nsCString expectedPathnameRegexp("^(.*)$"); 820 expectedMatcher.inner.filter = 'x'; 821 expectedMatcher.inner.allow_empty = true; 822 ASSERT_EQ(pathnameStr, expectedPathnamePatternString); 823 } 824 825 void assert_pattern_result(UrlpResult& res) { 826 ASSERT_TRUE(res.mProtocol.isSome()); 827 ASSERT_TRUE(res.mUsername.isSome()); 828 ASSERT_TRUE(res.mPassword.isSome()); 829 ASSERT_TRUE(res.mHostname.isSome()); 830 ASSERT_TRUE(res.mPort.isSome()); 831 ASSERT_TRUE(res.mPathname.isSome()); 832 ASSERT_TRUE(res.mSearch.isSome()); 833 ASSERT_TRUE(res.mHash.isSome()); 834 ASSERT_TRUE(res.mInputs.Length() == 1); 835 } 836 837 TEST(TestURLPatternGlue, UrlPatternExecFromString) 838 { 839 nsCString str(":café://:foo"); 840 UrlpOptions options = {.ignore_case = false}; 841 UrlpPattern pattern{}; 842 bool res = urlp_parse_pattern_from_string(&str, nullptr, options, &pattern); 843 ASSERT_TRUE(res); 844 ASSERT_TRUE(pattern._0); 845 846 nsCString inputString("https://example.com/"); 847 UrlpInput input = CreateUrlpInput(inputString); 848 Optional<nsAutoCString> execBaseUrl; 849 Optional<UrlpResult> res2 = UrlpPatternExec(pattern, input, execBaseUrl); 850 851 ASSERT_TRUE(res2.isNothing()); 852 } 853 854 TEST(TestURLPatternGlue, UrlPatternExecFromInit) 855 { 856 UrlpPattern pattern{}; 857 auto init = CreateSimpleInit("https"_ns, "example.com"_ns, "/"_ns); 858 UrlpOptions options = {.ignore_case = false}; 859 bool res = urlp_parse_pattern_from_init(&init, options, &pattern); 860 ASSERT_TRUE(res); 861 ASSERT_TRUE(pattern._0); 862 863 UrlpInput input = CreateUrlpInput(init); 864 Optional<nsAutoCString> execBaseUrl; 865 Optional<UrlpResult> res2 = UrlpPatternExec(pattern, input, execBaseUrl); 866 ASSERT_TRUE(res2.isSome()); 867 assert_pattern_result(*res2); 868 ASSERT_EQ(res2->mProtocol->mInput, "https"); 869 ASSERT_EQ(res2->mUsername->mInput, ""_ns); 870 ASSERT_EQ(res2->mPassword->mInput, ""_ns); 871 ASSERT_EQ(res2->mHostname->mInput, "example.com"); 872 ASSERT_EQ(res2->mPort->mInput, ""_ns); 873 ASSERT_EQ(res2->mPathname->mInput, "/"_ns); 874 ASSERT_EQ(res2->mSearch->mInput, ""_ns); 875 ASSERT_EQ(res2->mHash->mInput, ""_ns); 876 }