File indexing completed on 2024-11-17 04:55:15
0001 /* 0002 SPDX-License-Identifier: MPL-2.0 0003 */ 0004 0005 /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 0006 * This Source Code Form is subject to the terms of the Mozilla Public 0007 * License, v. 2.0. If a copy of the MPL was not distributed with this 0008 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 0009 0010 #include <string.h> 0011 #include <fstream> 0012 #include <sstream> 0013 #include <string> 0014 #include <vector> 0015 #include <cerrno> 0016 #include <algorithm> 0017 #include <iostream> 0018 #include <set> 0019 #include "./CppUnitLite/TestHarness.h" 0020 #include "./CppUnitLite/Test.h" 0021 #include "./ad_block_client.h" 0022 #include "./hash_set.h" 0023 #include "./util.h" 0024 0025 using std::string; 0026 using std::vector; 0027 using std::endl; 0028 using std::set; 0029 using std::cout; 0030 0031 bool testFilter(const char *rawFilter, FilterType expectedFilterType, 0032 FilterOption expectedFilterOption, 0033 const char *expectedData, 0034 set<string> &&blocked, // NOLINT 0035 set<string> &¬Blocked) { // NOLINT 0036 Filter filter; 0037 parseFilter(rawFilter, &filter); 0038 0039 if (filter.filterOption != expectedFilterOption) { 0040 cout << "Actual filter option: " << filter.filterOption 0041 << endl << "Expected: " << expectedFilterOption << endl; 0042 return false; 0043 } 0044 0045 if (filter.filterType != expectedFilterType) { 0046 cout << "Actual filter type: " << filter.filterType 0047 << endl << "Expected: " << expectedFilterType << endl; 0048 return false; 0049 } 0050 0051 if (strcmp(filter.data, expectedData)) { 0052 cout << "Actual filter data: " << filter.data 0053 << endl << "Expected: " << expectedData << endl; 0054 return false; 0055 } 0056 0057 bool ret = true; 0058 string lastChecked; 0059 std::for_each(blocked.begin(), blocked.end(), 0060 [&filter, &ret, &lastChecked, &expectedFilterOption](string const &s) { 0061 const FilterOption filterOptions = static_cast<FilterOption>( 0062 expectedFilterOption & FOResourcesOnly); 0063 ret = ret && filter.matches(s.c_str(), filterOptions); 0064 lastChecked = s; 0065 }); 0066 if (!ret) { 0067 cout << "Should match but did not: " << lastChecked.c_str() << endl; 0068 return false; 0069 } 0070 0071 std::for_each(notBlocked.begin(), notBlocked.end(), 0072 [&filter, &ret, &lastChecked, &expectedFilterOption](string const &s) { 0073 const auto filterOptions = static_cast<FilterOption>( 0074 expectedFilterOption & FOResourcesOnly); 0075 ret = ret && !filter.matches(s.c_str(), filterOptions); 0076 lastChecked = s; 0077 }); 0078 if (!ret) { 0079 cout << "Should NOT match but did: " << lastChecked.c_str() << endl; 0080 return false; 0081 } 0082 0083 return true; 0084 } 0085 0086 TEST(client, parseFilterMatchesFilter) { 0087 CHECK(testFilter("/banner/*/img", 0088 FTNoFilterType, 0089 FONoFilterOption, 0090 "/banner/*/img", 0091 { 0092 "http://example.com/banner/foo/img", 0093 "http://example.com/banner/foo/bar/img?param", 0094 "http://example.com/banner//img/foo", 0095 "http://example.com/banner//img.gif", 0096 }, { 0097 "http://example.com/banner", 0098 "http://example.com/banner/", 0099 "http://example.com/banner/img", 0100 "http://example.com/img/banner/", 0101 })); 0102 0103 CHECK(testFilter("/banner/*/img^", 0104 FTNoFilterType, 0105 FONoFilterOption, 0106 "/banner/*/img^", 0107 { 0108 "http://example.com/banner/foo/img", 0109 "http://example.com/banner/foo/bar/img?param", 0110 "http://example.com/banner//img/foo", 0111 }, { 0112 "http://example.com/banner/img", 0113 "http://example.com/banner/foo/imgraph", 0114 "http://example.com/banner/foo/img.gif", 0115 })); 0116 0117 CHECK(testFilter("||ads.example.com^", 0118 static_cast<FilterType>(FTHostAnchored | FTHostOnly), 0119 FONoFilterOption, 0120 "ads.example.com^", 0121 { 0122 "http://ads.example.com/foo.gif", 0123 "http://server1.ads.example.com/foo.gif", 0124 "https://ads.example.com:8000/", 0125 }, { 0126 "http://ads.example.com.ua/foo.gif", 0127 "http://example.com/redirect/http://ads.example.com/", 0128 })); 0129 0130 CHECK(testFilter("|http://example.com/|", 0131 static_cast<FilterType>(FTLeftAnchored | FTRightAnchored), 0132 FONoFilterOption, 0133 "http://example.com/", 0134 { 0135 "http://example.com/" 0136 }, { 0137 "http://example.com/foo.gif", 0138 "http://example.info/redirect/http://example.com/", 0139 })); 0140 0141 CHECK(testFilter("swf|", 0142 FTRightAnchored, 0143 FONoFilterOption, 0144 "swf", 0145 { 0146 "http://example.com/annoyingflash.swf", 0147 }, 0148 { 0149 "http://example.com/swf/index.html" 0150 })); 0151 0152 CHECK(testFilter("|http://baddomain.example/", 0153 FTLeftAnchored, 0154 FONoFilterOption, 0155 "http://baddomain.example/", 0156 { 0157 "http://baddomain.example/banner.gif", 0158 }, 0159 { 0160 "http://gooddomain.example/analyze?http://baddomain.example", 0161 })); 0162 0163 CHECK(testFilter("||example.com/banner.gif", 0164 FTHostAnchored, 0165 FONoFilterOption, 0166 "example.com/banner.gif", 0167 { 0168 "http://example.com/banner.gif", 0169 "https://example.com/banner.gif", 0170 "http://www.example.com/banner.gif", 0171 }, 0172 { 0173 "http://badexample.com/banner.gif", 0174 "http://gooddomain.example/analyze?http://example.com/banner.gif", 0175 "http://example.com.au/banner.gif", 0176 "http://example.com/banner2.gif", 0177 })); 0178 0179 CHECK(testFilter("http://example.com^", 0180 FTNoFilterType, 0181 FONoFilterOption, 0182 "http://example.com^", 0183 { 0184 "http://example.com/", 0185 "http://example.com:8000/ ", 0186 }, 0187 {})); 0188 0189 CHECK(testFilter("^example.com^", 0190 FTNoFilterType, 0191 FONoFilterOption, 0192 "^example.com^", 0193 { 0194 "http://example.com:8000/foo.bar?a=12&b=%D1%82%D0%B5%D1%81%D1%82", 0195 }, 0196 {})); 0197 CHECK(testFilter("^%D1%82%D0%B5%D1%81%D1%82^", 0198 FTNoFilterType, 0199 FONoFilterOption, 0200 "^%D1%82%D0%B5%D1%81%D1%82^", 0201 { 0202 "http://example.com:8000/foo.bar?a=12&b=%D1%82%D0%B5%D1%81%D1%82", 0203 }, 0204 { 0205 "http://example.com:8000/foo.bar?a=12&b%D1%82%D0%B5%D1%81%D1%823", 0206 })); 0207 CHECK(testFilter("^foo.bar^", 0208 FTNoFilterType, 0209 FONoFilterOption, 0210 "^foo.bar^", 0211 { 0212 "http://example.com:8000/foo.bar?a=12&b=%D1%82%D0%B5%D1%81%D1%82" 0213 }, 0214 {})); 0215 CHECK(testFilter("^promotion^", 0216 FTNoFilterType, 0217 FONoFilterOption, 0218 "^promotion^", 0219 { 0220 "http://test.com/promotion/test" 0221 }, 0222 { 0223 })); 0224 #ifdef ENABLE_REGEX 0225 CHECK(testFilter("/banner[0-9]+/", 0226 FTRegex, 0227 FONoFilterOption, 0228 "banner[0-9]+", 0229 { 0230 "banner123", 0231 "testbanner1" 0232 }, 0233 { 0234 "banners", 0235 "banners123" 0236 })); 0237 #endif 0238 CHECK(testFilter( 0239 "||static.tumblr.com/dhqhfum/WgAn39721/cfh_header_banner_v2.jpg", 0240 FTHostAnchored, 0241 FONoFilterOption, 0242 "static.tumblr.com/dhqhfum/WgAn39721/cfh_header_banner_v2.jpg", 0243 { 0244 "http://static.tumblr.com/dhqhfum/WgAn39721/cfh_header_banner_v2.jpg" 0245 }, 0246 {})); 0247 0248 CHECK(testFilter("||googlesyndication.com/safeframe/$third-party", 0249 FTHostAnchored, 0250 FOThirdParty, 0251 "googlesyndication.com/safeframe/", 0252 { 0253 "http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html" 0254 "#xpc=sf-gdn-exp-2&p=http%3A//slashdot.org;", 0255 }, 0256 {})); 0257 CHECK(testFilter("||googlesyndication.com/safeframe/$third-party,script", 0258 FTHostAnchored, 0259 static_cast<FilterOption>(FOThirdParty|FOScript), 0260 "googlesyndication.com/safeframe/", 0261 { 0262 "http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html" 0263 "#xpc=sf-gdn-exp-2&p=http%3A//slashdot.org;", 0264 }, 0265 {})); 0266 } 0267 0268 bool checkMatch(const char *rules, 0269 set<string> &&blocked, // NOLINT 0270 set<string> &¬Blocked, // NOLINT 0271 vector<string> &&tags) { // NOLINT 0272 AdBlockClient clients[2]; 0273 char * buffer = nullptr; 0274 for (int i = 0; i < 2; i++) { 0275 AdBlockClient &client = clients[i]; 0276 if (i == 0) { 0277 client.parse(rules); 0278 int size; 0279 buffer = clients[0].serialize(&size); 0280 } else if (!client.deserialize(buffer)) { 0281 cout << "Deserialization failed" << endl; 0282 delete[] buffer; 0283 return false; 0284 // The second else clause is for valgrind only 0285 } else if (!client.deserialize(buffer)) { 0286 cout << "Deserialization failed" << endl; 0287 delete[] buffer; 0288 return false; 0289 } 0290 std::for_each(tags.begin(), tags.end(), 0291 [&client](string const &tag) { 0292 client.addTag(tag); 0293 }); 0294 0295 bool ret = true; 0296 string lastChecked; 0297 std::for_each(blocked.begin(), blocked.end(), 0298 [&client, &lastChecked, &ret](string const &s) { 0299 ret = ret && client.matches(s.c_str()); 0300 lastChecked = s; 0301 }); 0302 if (!ret) { 0303 cout << "Should match but did not: " << lastChecked.c_str() << endl; 0304 delete[] buffer; 0305 return false; 0306 } 0307 0308 std::for_each(notBlocked.begin(), notBlocked.end(), 0309 [&client, &ret, &lastChecked](string const &s) { 0310 ret = ret && !client.matches(s.c_str()); 0311 lastChecked = s; 0312 }); 0313 if (!ret) { 0314 cout << "Should NOT match but did: " << lastChecked.c_str() << endl; 0315 delete[] buffer; 0316 return false; 0317 } 0318 } 0319 delete[] buffer; 0320 return true; 0321 } 0322 0323 TEST(client, exceptionRules) { 0324 CHECK(checkMatch("adv\n" 0325 "@@advice.", 0326 { 0327 "http://example.com/advert.html" 0328 }, { 0329 "http://example.com/advice.html", 0330 }, {})); 0331 0332 CHECK(checkMatch("@@advice.\n" 0333 "adv", 0334 { 0335 "http://example.com/advert.html" 0336 }, { 0337 "http://example.com/advice.html" 0338 }, {})); 0339 CHECK(checkMatch("@@|http://example.com\n" 0340 "@@advice.\n" 0341 "adv\n" 0342 "!foo", 0343 { 0344 "http://examples.com/advert.html", 0345 }, { 0346 "http://example.com/advice.html", 0347 "http://example.com/advert.html", 0348 "http://examples.com/advice.html", 0349 "http://examples.com/#!foo", 0350 }, {})); 0351 CHECK(checkMatch("/ads/freewheel/*\n" 0352 "@@||turner.com^*/ads/freewheel/*/" 0353 "AdManager.js$domain=cnn.com", 0354 { 0355 }, { 0356 "http://z.cdn.turner.com/xslo/cvp/ads/freewheel/js/0/AdManager.js", 0357 }, {})); 0358 CHECK(checkMatch("^promotion^", 0359 { 0360 "http://yahoo.co.jp/promotion/imgs" 0361 }, {}, {})); 0362 0363 CHECK(checkMatch("^ads^", 0364 { 0365 "http://yahoo.co.jp/ads/imgs", 0366 "http://yahoo.co.jp/ads", 0367 "http://yahoo.co.jp/ads?xyz", 0368 "http://yahoo.co.jp/xyz?ads", 0369 }, { 0370 "http://yahoo.co.jp/uploads/imgs", 0371 "http://yahoo.co.jp/adsx/imgs", 0372 "http://yahoo.co.jp/adsshmads/imgs", 0373 "ads://ads.co.ads/aads", 0374 }, {})); 0375 } 0376 0377 TEST(client, tagTests) { 0378 // No matching tags should not match a tagged filter 0379 CHECK(checkMatch("adv$tag=stuff\n" 0380 "somelongpath/test$tag=stuff\n" 0381 "||brianbondy.com/$tag=brian\n" 0382 "||brave.com$tag=brian", {}, { 0383 "http://example.com/advert.html", 0384 "http://example.com/somelongpath/test/2.html", 0385 "https://brianbondy.com/about", 0386 "https://brave.com/about" 0387 }, {})); 0388 // A matching tag should match a tagged filter 0389 CHECK(checkMatch("adv$tag=stuff\n" 0390 "somelongpath/test$tag=stuff\n" 0391 "||brianbondy.com/$tag=brian\n" 0392 "||brave.com$tag=brian", { 0393 "http://example.com/advert.html", 0394 "http://example.com/somelongpath/test/2.html", 0395 "https://brianbondy.com/about", 0396 "https://brave.com/about" 0397 }, {}, { 0398 "stuff", "brian" 0399 })); 0400 // A tag which doesn't match shouldn't match 0401 CHECK(checkMatch("adv$tag=stuff\n" 0402 "somelongpath/test$tag=stuff\n" 0403 "||brianbondy.com/$tag=brian\n" 0404 "||brave.com$tag=brian", { 0405 }, { 0406 "http://example.com/advert.html", 0407 "http://example.com/somelongpath/test/2.html", 0408 "https://brianbondy.com/about", 0409 "https://brave.com/about" 0410 }, { 0411 "filtertag1", "filtertag2" 0412 })); 0413 } 0414 0415 struct OptionRuleData { 0416 OptionRuleData(const char *testUrl, FilterOption context, 0417 const char *contextDomain, bool shouldBlock) { 0418 this->testUrl = testUrl; 0419 this->context = context; 0420 this->contextDomain = contextDomain; 0421 this->shouldBlock = shouldBlock; 0422 } 0423 0424 bool operator<(const OptionRuleData& rhs) const { 0425 return this->testUrl - rhs.testUrl < 0; 0426 } 0427 0428 const char *testUrl; 0429 FilterOption context; 0430 const char *contextDomain; 0431 bool shouldBlock; 0432 }; 0433 0434 bool checkOptionRule(const char *rules, 0435 set<OptionRuleData> &&optionTests) { // NOLINT 0436 AdBlockClient client; 0437 client.parse(rules); 0438 0439 bool fail = false; 0440 std::for_each(optionTests.begin(), optionTests.end(), 0441 [&client, &fail](OptionRuleData const &data) { 0442 bool matches = client.matches(data.testUrl, 0443 data.context, data.contextDomain); 0444 if (matches != data.shouldBlock) { 0445 cout << "Expected to block: " << data.shouldBlock 0446 << endl << "Actual blocks: " << matches << endl; 0447 fail = true; 0448 return; 0449 } 0450 }); 0451 if (fail) { 0452 return false; 0453 } 0454 0455 return true; 0456 } 0457 0458 // Option rules 0459 TEST(client, optionRules) { 0460 CHECK(checkOptionRule("||example.com", 0461 { 0462 OptionRuleData("http://example.com", 0463 FOThirdParty, nullptr, true), 0464 OptionRuleData("http://example2.com", FOThirdParty, nullptr, false), 0465 OptionRuleData("http://example.com", FONotThirdParty, nullptr, true), 0466 })); 0467 0468 CHECK(checkOptionRule("||example.com^$third-party", 0469 { 0470 OptionRuleData("http://example.com", FOScript, "brianbondy.com", true), 0471 OptionRuleData("http://example.com", FOScript, "example.com", false), 0472 OptionRuleData("http://ad.example.com", FOScript, "brianbondy.com", true), 0473 OptionRuleData("http://ad.example.com", FOScript, "example.com", false), 0474 OptionRuleData("http://example2.com", FOScript, "brianbondy.com", false), 0475 OptionRuleData("http://example2.com", FOScript, "example.com", false), 0476 OptionRuleData("http://example.com.au", FOScript, 0477 "brianbondy.com", false), 0478 OptionRuleData("http://example.com.au", FOScript, "example.com", false), 0479 })); 0480 0481 // We should block ping rules if the resource type is FOPing 0482 CHECK(checkOptionRule("||example.com^$ping", 0483 { 0484 OptionRuleData("http://example.com", FOPing, "example.com", true), 0485 OptionRuleData("http://example.com", FOImage, "example.com", false), 0486 })); 0487 0488 // Make sure we ignore popup rules for now 0489 CHECK(checkOptionRule("||example.com^$popup", 0490 { 0491 OptionRuleData("http://example.com", FOPopup, "example.com", false), 0492 })); 0493 0494 CHECK(checkOptionRule("||example.com^$third-party,~script", 0495 { 0496 OptionRuleData("http://example.com", 0497 static_cast<FilterOption>(FOThirdParty | FOScript), nullptr, false), 0498 OptionRuleData("http://example.com", FOOther, nullptr, true), 0499 OptionRuleData("http://example2.com", 0500 static_cast<FilterOption>(FOThirdParty | FOOther), nullptr, false), 0501 OptionRuleData("http://example.com", 0502 static_cast<FilterOption>(FONotThirdParty | FOOther), nullptr, false), 0503 })); 0504 0505 CHECK(checkOptionRule("adv$domain=example.com|example.net", 0506 { 0507 OptionRuleData("http://example.net/adv", 0508 FONoFilterOption, "example.net", true), 0509 OptionRuleData("http://somewebsite.com/adv", 0510 FONoFilterOption, "example.com", true), 0511 OptionRuleData("http://www.example.net/adv", 0512 FONoFilterOption, "www.example.net", true), 0513 OptionRuleData("http://my.subdomain.example.com/adv", 0514 FONoFilterOption, "my.subdomain.example.com", true), 0515 OptionRuleData("http://my.subdomain.example.com/adv", 0516 FONoFilterOption, "my.subdomain.example.com", true), 0517 OptionRuleData("http://example.com/adv", 0518 FONoFilterOption, "badexample.com", false), 0519 OptionRuleData("http://example.com/adv", 0520 FONoFilterOption, "otherdomain.net", false), 0521 OptionRuleData("http://example.net/ad", 0522 FONoFilterOption, "example.net", false), 0523 })); 0524 0525 CHECK(checkOptionRule("adv$domain=example.com|~foo.example.com", 0526 { 0527 OptionRuleData("http://example.net/adv", 0528 FONoFilterOption, "example.com", true), 0529 OptionRuleData("http://example.net/adv", 0530 FONoFilterOption, "foo.example.com", false), 0531 OptionRuleData("http://example.net/adv", 0532 FONoFilterOption, "www.foo.example.com", false), 0533 })); 0534 0535 CHECK(checkOptionRule("adv$domain=~example.com|foo.example.com", 0536 { 0537 OptionRuleData("http://example.net/adv", 0538 FONoFilterOption, "example.com", false), 0539 OptionRuleData("http://example.net/adv", 0540 FONoFilterOption, "foo.example.com", true), 0541 OptionRuleData("http://example.net/adv", 0542 FONoFilterOption, "www.foo.example.com", true), 0543 })); 0544 0545 CHECK(checkOptionRule("adv$domain=~example.com", 0546 { 0547 OptionRuleData("http://example.net/adv", 0548 FONoFilterOption, "otherdomain.com", true), 0549 OptionRuleData("http://somewebsite.com/adv", 0550 FONoFilterOption, "example.com", false), 0551 })); 0552 0553 CHECK(checkOptionRule("adv$domain=~example.com|~example.net", 0554 { 0555 OptionRuleData("http://example.net/adv", 0556 FONoFilterOption, "example.net", false), 0557 OptionRuleData("http://somewebsite.com/adv", 0558 FONoFilterOption, "example.com", false), 0559 OptionRuleData("http://www.example.net/adv", 0560 FONoFilterOption, "www.example.net", false), 0561 OptionRuleData("http://my.subdomain.example.com/adv", 0562 FONoFilterOption, "my.subdomain.example.com", false), 0563 OptionRuleData("http://example.com/adv", 0564 FONoFilterOption, "badexample.com", true), 0565 OptionRuleData("http://example.com/adv", 0566 FONoFilterOption, "otherdomain.net", true), 0567 OptionRuleData("http://example.net/ad", 0568 FONoFilterOption, "example.net", false), 0569 })); 0570 0571 CHECK(checkOptionRule("adv$domain=example.com|~example.net", 0572 { 0573 OptionRuleData("http://example.net/adv", 0574 FONoFilterOption, "example.net", false), 0575 OptionRuleData("http://somewebsite.com/adv", 0576 FONoFilterOption, "example.com", true), 0577 OptionRuleData("http://www.example.net/adv", 0578 FONoFilterOption, "www.example.net", false), 0579 OptionRuleData("http://my.subdomain.example.com/adv", 0580 FONoFilterOption, "my.subdomain.example.com", true), 0581 OptionRuleData("http://example.com/adv", 0582 FONoFilterOption, "badexample.com", false), 0583 OptionRuleData("http://example.com/adv", 0584 FONoFilterOption, "otherdomain.net", false), 0585 OptionRuleData("http://example.net/ad", 0586 FONoFilterOption, "example.net", false), 0587 })); 0588 0589 CHECK(checkOptionRule( 0590 "adv$domain=example.com|~foo.example.com,script", 0591 { 0592 OptionRuleData("http://example.net/adv", 0593 FOScript, "example.com", true), 0594 OptionRuleData("http://example.net/adv", 0595 FOScript, "foo.example.com", false), 0596 OptionRuleData("http://example.net/adv", 0597 FOScript, "www.foo.example.com", false), 0598 OptionRuleData("http://example.net/adv", 0599 FOOther, "example.com", false), 0600 OptionRuleData("http://example.net/adv", 0601 FOOther, "foo.example.com", false), 0602 OptionRuleData("http://example.net/adv", 0603 FOOther, "www.foo.example.com", false), 0604 })); 0605 0606 CHECK(checkOptionRule("adv\n" 0607 "@@advice.$~script", 0608 { 0609 OptionRuleData("http://example.com/advice.html", 0610 FOOther, nullptr, false), 0611 OptionRuleData("http://example.com/advice.html", 0612 FOScript, nullptr, true), 0613 OptionRuleData("http://example.com/advert.html", 0614 FOOther, nullptr, true), 0615 OptionRuleData("http://example.com/advert.html", 0616 FOScript, nullptr, true), 0617 })); 0618 0619 // Single matching context domain to domain list 0620 CHECK(checkOptionRule( 0621 "||mzstatic.com^$image,object-subrequest,domain=dailymotion.com", 0622 { 0623 OptionRuleData("http://www.dailymotion.com", 0624 FONoFilterOption, "dailymotion.com", false), 0625 })); 0626 0627 // Third party flags work correctly 0628 CHECK(checkOptionRule( 0629 "||s1.wp.com^$subdocument,third-party", 0630 { 0631 OptionRuleData("http://s1.wp.com/_static", 0632 FOScript, "windsorstar.com", false), 0633 })); 0634 0635 // Third party flags work correctly 0636 CHECK(checkOptionRule( 0637 "/scripts/ad.", 0638 { 0639 OptionRuleData("http://a.fsdn.com/sd/js/scripts/ad.js?release_20160112", 0640 FOScript, "slashdot.org", true), 0641 })); 0642 } 0643 0644 struct ListCounts { 0645 size_t filters; 0646 size_t cosmeticFilters; 0647 size_t htmlFilters; 0648 size_t exceptions; 0649 }; 0650 0651 ListCounts easyList = { 36342, 32667, 0, 5174 }; 0652 ListCounts easyPrivacy = { 15144, 0, 0, 1202 }; 0653 ListCounts ublockUnbreak = { 133, 106, 0, 494 }; 0654 ListCounts braveUnbreak = { 79, 0, 0, 32 }; 0655 ListCounts disconnectSimpleMalware = { 2450, 0, 0, 0 }; 0656 ListCounts spam404MainBlacklist = { 5629, 166, 0, 0 }; 0657 0658 // Should parse EasyList without failing 0659 TEST(client, parse_easylist) { 0660 string && fileContents = // NOLINT 0661 getFileContents("./test/data/easylist.txt"); 0662 AdBlockClient client; 0663 client.parse(fileContents.c_str()); 0664 0665 CHECK(compareNums(client.numFilters + 0666 client.numNoFingerprintFilters + 0667 client.numNoFingerprintDomainOnlyFilters + 0668 client.numNoFingerprintAntiDomainOnlyFilters + 0669 client.hostAnchoredHashSet->GetSize(), 0670 easyList.filters)); 0671 CHECK(compareNums(client.numCosmeticFilters, easyList.cosmeticFilters)); 0672 CHECK(compareNums(client.numHtmlFilters, easyList.htmlFilters)); 0673 CHECK(compareNums(client.numExceptionFilters + 0674 client.numNoFingerprintExceptionFilters + 0675 client.numNoFingerprintDomainOnlyExceptionFilters + 0676 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0677 client.hostAnchoredExceptionHashSet->GetSize(), 0678 easyList.exceptions)); 0679 } 0680 0681 // Should parse EasyPrivacy without failing 0682 TEST(client, parse_easyprivacy) { 0683 string && fileContents = // NOLINT 0684 getFileContents("./test/data/easyprivacy.txt"); 0685 AdBlockClient client; 0686 client.parse(fileContents.c_str()); 0687 0688 CHECK(compareNums(client.numFilters + 0689 client.numNoFingerprintFilters + 0690 client.numNoFingerprintDomainOnlyFilters + 0691 client.numNoFingerprintAntiDomainOnlyFilters + 0692 client.hostAnchoredHashSet->GetSize(), 0693 easyPrivacy.filters)); 0694 CHECK(compareNums(client.numCosmeticFilters, easyPrivacy.cosmeticFilters)); 0695 CHECK(compareNums(client.numHtmlFilters, easyPrivacy.htmlFilters)); 0696 CHECK(compareNums(client.numExceptionFilters + 0697 client.numNoFingerprintExceptionFilters + 0698 client.numNoFingerprintDomainOnlyExceptionFilters + 0699 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0700 client.hostAnchoredExceptionHashSet->GetSize(), 0701 easyPrivacy.exceptions)); 0702 } 0703 0704 // Should parse ublock-unbreak list without failing 0705 TEST(client, parse_ublock_unbreak) { 0706 string && fileContents = // NOLINT 0707 getFileContents("./test/data/ublock-unbreak.txt"); 0708 AdBlockClient client; 0709 client.parse(fileContents.c_str()); 0710 0711 CHECK(compareNums(client.numFilters + 0712 client.numNoFingerprintFilters + 0713 client.numNoFingerprintDomainOnlyFilters + 0714 client.numNoFingerprintAntiDomainOnlyFilters + 0715 client.hostAnchoredHashSet->GetSize(), 0716 ublockUnbreak.filters)); 0717 CHECK(compareNums(client.numCosmeticFilters, ublockUnbreak.cosmeticFilters)); 0718 CHECK(compareNums(client.numHtmlFilters, ublockUnbreak.htmlFilters)); 0719 CHECK(compareNums(client.numExceptionFilters + 0720 client.numNoFingerprintExceptionFilters + 0721 client.numNoFingerprintDomainOnlyExceptionFilters + 0722 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0723 client.hostAnchoredExceptionHashSet->GetSize(), 0724 ublockUnbreak.exceptions)); 0725 } 0726 0727 // Should parse brave-unbreak list without failing 0728 TEST(client, parse_brave_unbreak) { 0729 string && fileContents = // NOLINT 0730 getFileContents("./test/data/brave-unbreak.txt"); 0731 AdBlockClient client; 0732 client.parse(fileContents.c_str()); 0733 0734 CHECK(compareNums(client.numFilters + 0735 client.numNoFingerprintFilters + 0736 client.numNoFingerprintDomainOnlyFilters + 0737 client.numNoFingerprintAntiDomainOnlyFilters + 0738 client.hostAnchoredHashSet->GetSize(), 0739 braveUnbreak.filters)); 0740 CHECK(compareNums(client.numCosmeticFilters, braveUnbreak.cosmeticFilters)); 0741 CHECK(compareNums(client.numHtmlFilters, braveUnbreak.htmlFilters)); 0742 CHECK(compareNums(client.numExceptionFilters + 0743 client.numNoFingerprintExceptionFilters + 0744 client.numNoFingerprintDomainOnlyExceptionFilters + 0745 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0746 client.hostAnchoredExceptionHashSet->GetSize(), 0747 braveUnbreak.exceptions)); 0748 } 0749 0750 // Should parse disconnect-simple-malware.txt list without failing 0751 TEST(client, parse_brave_disconnect_simple_malware) { 0752 string && fileContents = // NOLINT 0753 getFileContents("./test/data/disconnect-simple-malware.txt"); 0754 AdBlockClient client; 0755 client.parse(fileContents.c_str()); 0756 0757 CHECK(compareNums(client.numFilters + 0758 client.numNoFingerprintFilters + 0759 client.numNoFingerprintDomainOnlyFilters + 0760 client.numNoFingerprintAntiDomainOnlyFilters + 0761 client.hostAnchoredHashSet->GetSize(), 0762 disconnectSimpleMalware.filters)); 0763 CHECK(compareNums(client.numCosmeticFilters, 0764 disconnectSimpleMalware.cosmeticFilters)); 0765 CHECK(compareNums(client.numHtmlFilters, 0766 disconnectSimpleMalware.htmlFilters)); 0767 CHECK(compareNums(client.numExceptionFilters + 0768 client.numNoFingerprintExceptionFilters + 0769 client.numNoFingerprintDomainOnlyExceptionFilters + 0770 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0771 client.hostAnchoredExceptionHashSet->GetSize(), 0772 disconnectSimpleMalware.exceptions)); 0773 } 0774 0775 0776 // Should parse spam404-main-blacklist.txt list without failing 0777 TEST(client, parse_spam404_main_blacklist) { 0778 string && fileContents = // NOLINT 0779 getFileContents("./test/data/spam404-main-blacklist.txt"); 0780 AdBlockClient client; 0781 client.parse(fileContents.c_str()); 0782 0783 CHECK(compareNums(client.numFilters + 0784 client.numNoFingerprintFilters + 0785 client.numNoFingerprintDomainOnlyFilters + 0786 client.numNoFingerprintAntiDomainOnlyFilters + 0787 client.hostAnchoredHashSet->GetSize(), 0788 spam404MainBlacklist.filters)); 0789 CHECK(compareNums(client.numCosmeticFilters, 0790 spam404MainBlacklist.cosmeticFilters)); 0791 CHECK(compareNums(client.numHtmlFilters, spam404MainBlacklist.htmlFilters)); 0792 CHECK(compareNums(client.numExceptionFilters + 0793 client.numNoFingerprintExceptionFilters + 0794 client.numNoFingerprintDomainOnlyExceptionFilters + 0795 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0796 client.hostAnchoredExceptionHashSet->GetSize(), 0797 spam404MainBlacklist.exceptions)); 0798 0799 const char *urlToCheck = "http://excellentmovies.net/"; 0800 const char *currentPageDomain = "excellentmovies.net"; 0801 CHECK(client.matches(urlToCheck, FOImage, currentPageDomain)); 0802 } 0803 0804 0805 // Should parse lists without failing 0806 TEST(client, parse_multiList) { 0807 string && fileContentsEasylist = // NOLINT 0808 getFileContents("./test/data/easylist.txt"); 0809 0810 string && fileContentsEasyPrivacy = // NOLINT 0811 getFileContents("./test/data/easyprivacy.txt"); 0812 0813 string && fileContentsUblockUnbreak = // NOLINT 0814 getFileContents("./test/data/ublock-unbreak.txt"); 0815 0816 string && fileContentsBraveUnbreak = // NOLINT 0817 getFileContents("./test/data/brave-unbreak.txt"); 0818 0819 AdBlockClient client; 0820 client.parse(fileContentsEasylist.c_str()); 0821 client.parse(fileContentsEasyPrivacy.c_str()); 0822 client.parse(fileContentsUblockUnbreak.c_str()); 0823 client.parse(fileContentsBraveUnbreak.c_str()); 0824 0825 // I think counts are slightly off due to same rule hash set 0826 0827 /* 0828 CHECK(compareNums(client.numFilters + 0829 client.numNoFingerprintFilters + 0830 client.numNoFingerprintDomainOnlyFilters + 0831 client.numNoFingerprintAntiDomainOnlyFilters + 0832 client.hostAnchoredHashSet->GetSize(), 0833 easyList.filters + 0834 easyPrivacy.filters + 0835 ublockUnbreak.filters + 0836 braveUnbreak.filters)); 0837 */ 0838 CHECK(compareNums(client.numCosmeticFilters, 0839 easyList.cosmeticFilters + 0840 easyPrivacy.cosmeticFilters + 0841 ublockUnbreak.cosmeticFilters + 0842 braveUnbreak.cosmeticFilters)); 0843 0844 CHECK(compareNums(client.numHtmlFilters, 0845 easyList.htmlFilters+ 0846 easyPrivacy.htmlFilters+ 0847 ublockUnbreak.htmlFilters + 0848 braveUnbreak.htmlFilters)); 0849 /* 0850 CHECK(compareNums(client.numExceptionFilters + 0851 client.hostAnchoredExceptionHashSet->GetSize() + 0852 client.numNoFingerprintExceptionFilters, 0853 client.numNoFingerprintDomainOnlyExceptionFilters + 0854 client.numNoFingerprintAntiDomainOnlyExceptionFilters + 0855 easyList.exceptions + 0856 easyPrivacy.exceptions + 0857 ublockUnbreak.exceptions + 0858 braveUnbreak.exceptions)); 0859 */ 0860 } 0861 0862 // Should parse lists without failing 0863 TEST(client, parse_malware_multiList) { 0864 string && fileContentsSpam404 = // NOLINT 0865 getFileContents("./test/data/spam404-main-blacklist.txt"); 0866 0867 string && fileContentsDisconnectSimpleMalware = // NOLINT 0868 getFileContents("./test/data/disconnect-simple-malware.txt"); 0869 0870 AdBlockClient client; 0871 client.parse(fileContentsSpam404.c_str()); 0872 client.parse(fileContentsDisconnectSimpleMalware.c_str()); 0873 0874 // I think counts are slightly off due to same rule hash set 0875 0876 /* 0877 CHECK(compareNums(client.numFilters + 0878 client.numNoFingerprintFilters + 0879 client.numNoFingerprintDomainOnlyFilters + 0880 client.numNoFingerprintAntiDomainOnlyFilters + 0881 client.hostAnchoredHashSet->GetSize(), 0882 disconnectSimpleMalware.filters + 0883 spam404MainBlacklist.filters)); 0884 */ 0885 CHECK(compareNums(client.numCosmeticFilters, 0886 disconnectSimpleMalware.cosmeticFilters + 0887 spam404MainBlacklist.cosmeticFilters)); 0888 0889 CHECK(compareNums(client.numHtmlFilters, 0890 disconnectSimpleMalware.htmlFilters + 0891 spam404MainBlacklist.htmlFilters)); 0892 0893 CHECK(compareNums(client.numExceptionFilters + 0894 client.hostAnchoredExceptionHashSet->GetSize() + 0895 client.numNoFingerprintExceptionFilters + 0896 client.numNoFingerprintAntiDomainOnlyExceptionFilters, 0897 disconnectSimpleMalware.exceptions+ 0898 spam404MainBlacklist.exceptions)); 0899 } 0900 0901 0902 // Calling parse amongst 2 different lists should preserve both sets of rules 0903 TEST(multipleParse, multipleParse2) { 0904 AdBlockClient client; 0905 client.parse("adv\n" 0906 "@@test\n" 0907 "###test\n" 0908 "a.com$$script[src]\n"); 0909 client.parse("adv2\n" 0910 "@@test2\n" 0911 "###test2\n" 0912 "adv3\n" 0913 "@@test3\n" 0914 "###test3\n" 0915 "b.com$$script[src]\n"); 0916 0917 CHECK(compareNums(client.numFilters + 0918 client.numNoFingerprintFilters + 0919 client.numNoFingerprintDomainOnlyFilters + 0920 client.numNoFingerprintAntiDomainOnlyFilters, 3)); 0921 CHECK(compareNums(client.numCosmeticFilters, 3)); 0922 CHECK(compareNums(client.numHtmlFilters, 2)); 0923 CHECK(compareNums(client.numExceptionFilters + 0924 client.numNoFingerprintExceptionFilters + 0925 client.numNoFingerprintDomainOnlyExceptionFilters + 0926 client.numNoFingerprintAntiDomainOnlyExceptionFilters, 3)); 0927 } 0928 0929 // Demo app test 0930 TEST(demoApp, demoApp2) { 0931 AdBlockClient client; 0932 client.parse("||googlesyndication.com/safeframe/$third-party"); 0933 const char *urlToCheck = 0934 "http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html"; 0935 const char *currentPageDomain = "slashdot.org"; 0936 CHECK(client.matches(urlToCheck, FOScript, currentPageDomain)); 0937 } 0938 0939 TEST(hostAnchoredFiltersParseCorrectly, hostAnchoredFiltersParseCorrectly2) { 0940 // Host anchor is calculated correctly 0941 Filter filter; 0942 parseFilter("||test.com$third-party", &filter); 0943 CHECK(!strcmp("test.com", filter.host)); 0944 0945 Filter filter2; 0946 parseFilter("||test.com/ok$third-party", &filter2); 0947 CHECK(!strcmp("test.com", filter2.host)); 0948 0949 Filter filter3; 0950 parseFilter("||test.com/ok", &filter3); 0951 CHECK(!strcmp("test.com", filter3.host)); 0952 0953 Filter filter4; 0954 Filter filter5; 0955 CHECK(filter4 == filter5); 0956 } 0957 0958 TEST(misc, misc2) { 0959 for (int i = 0; i < 256; i++) { 0960 if (i == static_cast<int>(':') || i == static_cast<int>('?') || 0961 i == static_cast<int>('/') || 0962 i == static_cast<int>('=') || i == static_cast<int>('^') || 0963 i == static_cast<int>('$')) { 0964 CHECK(isSeparatorChar(static_cast<char>(i))); 0965 } else { 0966 CHECK(!isSeparatorChar(static_cast<int>(static_cast<char>(i)))); 0967 } 0968 } 0969 } 0970 0971 0972 TEST(serializationTests, serializationTests2) { 0973 AdBlockClient client; 0974 client.parse( 0975 "||googlesyndication.com$third-party\n@@||googlesyndication.ca\na$explicitcancel"); 0976 int size; 0977 char * buffer = client.serialize(&size); 0978 0979 AdBlockClient client2; 0980 CHECK(client2.deserialize(buffer)); 0981 // For valgrind only 0982 client2.deserialize(buffer); 0983 0984 Filter f(static_cast<FilterType>(FTHostAnchored | FTHostOnly), FOThirdParty, 0985 FONoFilterOption, "googlesyndication.com", 21, nullptr, 0986 "googlesyndication.com"); 0987 Filter f2(FTNoFilterType, FOThirdParty, FONoFilterOption, 0988 "googleayndication.com", 21, nullptr, "googleayndication.com"); 0989 CHECK(client.hostAnchoredHashSet->Exists(f)); 0990 CHECK(client2.hostAnchoredHashSet->Exists(f)); 0991 CHECK(!client.hostAnchoredHashSet->Exists(f2)); 0992 CHECK(!client2.hostAnchoredHashSet->Exists(f2)); 0993 0994 Filter f3(static_cast<FilterType>(FTHostAnchored | FTHostOnly | FTException), 0995 FONoFilterOption, FONoFilterOption, "googlesyndication.ca", 0996 20, nullptr, "googlesyndication.ca"); 0997 Filter f4(FTNoFilterType, FONoFilterOption, FONoFilterOption, 0998 "googleayndication.ca", 20, nullptr, "googleayndication.ca"); 0999 CHECK(client.hostAnchoredExceptionHashSet->Exists(f3)); 1000 CHECK(client2.hostAnchoredExceptionHashSet->Exists(f3)); 1001 CHECK(!client.hostAnchoredExceptionHashSet->Exists(f4)); 1002 CHECK(!client2.hostAnchoredExceptionHashSet->Exists(f4)); 1003 CHECK(client.noFingerprintFilters[0].filterOption & FOExplicitCancel); 1004 CHECK(client2.noFingerprintFilters[0].filterOption & FOExplicitCancel); 1005 delete[] buffer; 1006 } 1007 1008 // Testing matchingFilter 1009 TEST(findMatchingFilters, basic) { 1010 AdBlockClient client; 1011 client.parse("||googlesyndication.com/safeframe/$third-party\n" 1012 "||brianbondy.com/ads"); 1013 const char *urlToCheck = 1014 "http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html"; 1015 const char *currentPageDomain = "slashdot.org"; 1016 1017 Filter none; 1018 Filter *matchingFilter = &none; 1019 Filter *matchingExceptionFilter = &none; 1020 1021 // Test finds a match 1022 CHECK(client.findMatchingFilters(urlToCheck, FOScript, currentPageDomain, 1023 &matchingFilter, &matchingExceptionFilter)); 1024 CHECK(matchingFilter) 1025 CHECK(matchingExceptionFilter == nullptr) 1026 CHECK(!strcmp(matchingFilter->data, "googlesyndication.com/safeframe/")); 1027 1028 // Test when no filter is found, returns false and sets out params to nullptr 1029 CHECK(!client.findMatchingFilters("ssafsdf.com", FOScript, currentPageDomain, 1030 &matchingFilter, &matchingExceptionFilter)); 1031 CHECK(matchingFilter == nullptr) 1032 CHECK(matchingExceptionFilter == nullptr) 1033 1034 // Parse that it finds exception filters correctly 1035 client.parse("@@safeframe\n"); 1036 CHECK(!client.findMatchingFilters(urlToCheck, FOScript, currentPageDomain, 1037 &matchingFilter, &matchingExceptionFilter)); 1038 CHECK(matchingFilter) 1039 CHECK(matchingExceptionFilter) 1040 CHECK(!strcmp(matchingFilter->data, "googlesyndication.com/safeframe/")); 1041 CHECK(!strcmp(matchingExceptionFilter->data, "safeframe")); 1042 } 1043 1044 // Testing matchingFilter 1045 TEST(matchesWithFilterInfo, basic) { 1046 AdBlockClient client; 1047 client.parse("||googlesyndication.com/safeframe/$third-party\n" 1048 "||brianbondy.com/ads"); 1049 const char *urlToCheck = 1050 "http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html"; 1051 const char *currentPageDomain = "slashdot.org"; 1052 1053 Filter none; 1054 Filter *matchingFilter = &none; 1055 Filter *matchingExceptionFilter = &none; 1056 1057 // Test finds a match 1058 CHECK(client.matches(urlToCheck, FOScript, currentPageDomain, 1059 &matchingFilter, &matchingExceptionFilter)); 1060 CHECK(matchingFilter) 1061 CHECK(matchingExceptionFilter == nullptr) 1062 CHECK(!strcmp(matchingFilter->data, "googlesyndication.com/safeframe/")); 1063 1064 // Test when no filter is found, returns false and sets out params to nullptr 1065 CHECK(!client.matches("ssafsdf.com", FOScript, currentPageDomain, 1066 &matchingFilter, &matchingExceptionFilter)); 1067 CHECK(matchingFilter == nullptr) 1068 CHECK(matchingExceptionFilter == nullptr) 1069 1070 // Parse that it finds exception filters correctly 1071 client.parse("@@safeframe\n"); 1072 CHECK(!client.matches(urlToCheck, FOScript, currentPageDomain, 1073 &matchingFilter, &matchingExceptionFilter)); 1074 CHECK(matchingFilter) 1075 CHECK(matchingExceptionFilter) 1076 CHECK(!strcmp(matchingFilter->data, "googlesyndication.com/safeframe/")); 1077 CHECK(!strcmp(matchingExceptionFilter->data, "safeframe")); 1078 1079 // Preserves explicitcancel and important options when matching 1080 client.clear(); 1081 client.parse("||brianbondy.com^$explicitcancel"); 1082 bool matches = (client.matches("https://brianbondy.com/t", FOScript, "test.com", 1083 &matchingFilter, &matchingExceptionFilter)); 1084 CHECK(matches) 1085 CHECK(matchingFilter) 1086 CHECK(matchingFilter->filterOption & FOExplicitCancel) 1087 CHECK(!matchingExceptionFilter) 1088 1089 client.clear(); 1090 client.parse("||brianbondy.com^$important"); 1091 CHECK(client.matches("https://brianbondy.com/t", FOScript, "test.com", 1092 &matchingFilter, &matchingExceptionFilter)) 1093 CHECK(matchingFilter) 1094 CHECK(matchingFilter->filterOption & FOImportant) 1095 CHECK(!matchingExceptionFilter) 1096 }