webrequest_rules_registry_unittest.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h" 6 7#include <string> 8#include <vector> 9 10#include "base/basictypes.h" 11#include "base/json/json_reader.h" 12#include "base/memory/linked_ptr.h" 13#include "base/message_loop/message_loop.h" 14#include "base/stl_util.h" 15#include "base/test/values_test_util.h" 16#include "base/values.h" 17#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" 18#include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 19#include "chrome/common/extensions/extension_test_util.h" 20#include "content/public/test/test_browser_thread.h" 21#include "extensions/common/matcher/url_matcher_constants.h" 22#include "net/base/request_priority.h" 23#include "net/url_request/url_request_test_util.h" 24#include "testing/gmock/include/gmock/gmock.h" 25#include "testing/gtest/include/gtest/gtest-message.h" 26#include "testing/gtest/include/gtest/gtest.h" 27 28namespace { 29const char kExtensionId[] = "ext1"; 30const char kExtensionId2[] = "ext2"; 31const char kRuleId1[] = "rule1"; 32const char kRuleId2[] = "rule2"; 33const char kRuleId3[] = "rule3"; 34const char kRuleId4[] = "rule4"; 35} // namespace 36 37using extension_test_util::LoadManifest; 38using extension_test_util::LoadManifestUnchecked; 39 40namespace extensions { 41 42using base::Value; 43using testing::HasSubstr; 44 45namespace helpers = extension_web_request_api_helpers; 46namespace keys = declarative_webrequest_constants; 47namespace keys2 = url_matcher_constants; 48 49class TestWebRequestRulesRegistry : public WebRequestRulesRegistry { 50 public: 51 explicit TestWebRequestRulesRegistry( 52 scoped_refptr<ExtensionInfoMap> extension_info_map) 53 : WebRequestRulesRegistry(NULL /*profile*/, NULL /* cache_delegate */), 54 num_clear_cache_calls_(0) { 55 SetExtensionInfoMapForTesting(extension_info_map); 56 } 57 58 // Returns how often the in-memory caches of the renderers were instructed 59 // to be cleared. 60 int num_clear_cache_calls() const { return num_clear_cache_calls_; } 61 62 // How many rules are there which have some conditions not triggered by URL 63 // matches. 64 size_t RulesWithoutTriggers() const { 65 return rules_with_untriggered_conditions_for_test().size(); 66 } 67 68 protected: 69 virtual ~TestWebRequestRulesRegistry() {} 70 71 virtual void ClearCacheOnNavigation() OVERRIDE { 72 ++num_clear_cache_calls_; 73 } 74 75 private: 76 int num_clear_cache_calls_; 77}; 78 79class WebRequestRulesRegistryTest : public testing::Test { 80 public: 81 WebRequestRulesRegistryTest() 82 : message_loop_(base::MessageLoop::TYPE_IO), 83 ui_(content::BrowserThread::UI, &message_loop_), 84 io_(content::BrowserThread::IO, &message_loop_) {} 85 86 virtual ~WebRequestRulesRegistryTest() {} 87 88 virtual void SetUp() OVERRIDE; 89 90 virtual void TearDown() OVERRIDE { 91 // Make sure that deletion traits of all registries are executed. 92 message_loop_.RunUntilIdle(); 93 } 94 95 // Returns a rule that roughly matches http://*.example.com and 96 // https://www.example.com and cancels it 97 linked_ptr<RulesRegistry::Rule> CreateRule1() { 98 base::ListValue* scheme_http = new base::ListValue(); 99 scheme_http->Append(new base::StringValue("http")); 100 base::DictionaryValue* http_condition_dict = new base::DictionaryValue(); 101 http_condition_dict->Set(keys2::kSchemesKey, scheme_http); 102 http_condition_dict->SetString(keys2::kHostSuffixKey, "example.com"); 103 base::DictionaryValue http_condition_url_filter; 104 http_condition_url_filter.Set(keys::kUrlKey, http_condition_dict); 105 http_condition_url_filter.SetString(keys::kInstanceTypeKey, 106 keys::kRequestMatcherType); 107 108 base::ListValue* scheme_https = new base::ListValue(); 109 scheme_http->Append(new base::StringValue("https")); 110 base::DictionaryValue* https_condition_dict = new base::DictionaryValue(); 111 https_condition_dict->Set(keys2::kSchemesKey, scheme_https); 112 https_condition_dict->SetString(keys2::kHostSuffixKey, "example.com"); 113 https_condition_dict->SetString(keys2::kHostPrefixKey, "www"); 114 base::DictionaryValue https_condition_url_filter; 115 https_condition_url_filter.Set(keys::kUrlKey, https_condition_dict); 116 https_condition_url_filter.SetString(keys::kInstanceTypeKey, 117 keys::kRequestMatcherType); 118 119 base::DictionaryValue action_dict; 120 action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType); 121 122 linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); 123 rule->id.reset(new std::string(kRuleId1)); 124 rule->priority.reset(new int(100)); 125 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy())); 126 rule->conditions.push_back( 127 linked_ptr<base::Value>(http_condition_url_filter.DeepCopy())); 128 rule->conditions.push_back( 129 linked_ptr<base::Value>(https_condition_url_filter.DeepCopy())); 130 return rule; 131 } 132 133 // Returns a rule that matches anything and cancels it. 134 linked_ptr<RulesRegistry::Rule> CreateRule2() { 135 base::DictionaryValue condition_dict; 136 condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType); 137 138 base::DictionaryValue action_dict; 139 action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType); 140 141 linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); 142 rule->id.reset(new std::string(kRuleId2)); 143 rule->priority.reset(new int(100)); 144 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy())); 145 rule->conditions.push_back( 146 linked_ptr<base::Value>(condition_dict.DeepCopy())); 147 return rule; 148 } 149 150 linked_ptr<RulesRegistry::Rule> CreateRedirectRule( 151 const std::string& destination) { 152 base::DictionaryValue condition_dict; 153 condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType); 154 155 base::DictionaryValue action_dict; 156 action_dict.SetString(keys::kInstanceTypeKey, keys::kRedirectRequestType); 157 action_dict.SetString(keys::kRedirectUrlKey, destination); 158 159 linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); 160 rule->id.reset(new std::string(kRuleId3)); 161 rule->priority.reset(new int(100)); 162 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy())); 163 rule->conditions.push_back( 164 linked_ptr<base::Value>(condition_dict.DeepCopy())); 165 return rule; 166 } 167 168 // Create a rule to ignore all other rules for a destination that 169 // contains index.html. 170 linked_ptr<RulesRegistry::Rule> CreateIgnoreRule() { 171 base::DictionaryValue condition_dict; 172 base::DictionaryValue* http_condition_dict = new base::DictionaryValue(); 173 http_condition_dict->SetString(keys2::kPathContainsKey, "index.html"); 174 condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType); 175 condition_dict.Set(keys::kUrlKey, http_condition_dict); 176 177 base::DictionaryValue action_dict; 178 action_dict.SetString(keys::kInstanceTypeKey, keys::kIgnoreRulesType); 179 action_dict.SetInteger(keys::kLowerPriorityThanKey, 150); 180 181 linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); 182 rule->id.reset(new std::string(kRuleId4)); 183 rule->priority.reset(new int(200)); 184 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy())); 185 rule->conditions.push_back( 186 linked_ptr<base::Value>(condition_dict.DeepCopy())); 187 return rule; 188 } 189 190 // Create a condition with the attributes specified. An example value of 191 // |attributes| is: "\"resourceType\": [\"stylesheet\"], \n". 192 linked_ptr<base::Value> CreateCondition(const std::string& attributes) { 193 std::string json_description = 194 "{ \n" 195 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"; 196 json_description += attributes; 197 json_description += "}"; 198 199 return linked_ptr<base::Value>( 200 base::test::ParseJson(json_description).release()); 201 } 202 203 // Create a rule with the ID |rule_id| and with conditions created from the 204 // |attributes| specified (one entry one condition). An example value of a 205 // string from |attributes| is: "\"resourceType\": [\"stylesheet\"], \n". 206 linked_ptr<RulesRegistry::Rule> CreateCancellingRule( 207 const char* rule_id, 208 const std::vector<const std::string*>& attributes) { 209 base::DictionaryValue action_dict; 210 action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType); 211 212 linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule); 213 rule->id.reset(new std::string(rule_id)); 214 rule->priority.reset(new int(1)); 215 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy())); 216 for (std::vector<const std::string*>::const_iterator it = 217 attributes.begin(); 218 it != attributes.end(); ++it) 219 rule->conditions.push_back(CreateCondition(**it)); 220 return rule; 221 } 222 223 protected: 224 base::MessageLoop message_loop_; 225 content::TestBrowserThread ui_; 226 content::TestBrowserThread io_; 227 // Two extensions with host permissions for all URLs and the DWR permission. 228 // Installation times will be so that |extension_| is older than 229 // |extension2_|. 230 scoped_refptr<Extension> extension_; 231 scoped_refptr<Extension> extension2_; 232 scoped_refptr<ExtensionInfoMap> extension_info_map_; 233}; 234 235void WebRequestRulesRegistryTest::SetUp() { 236 testing::Test::SetUp(); 237 238 std::string error; 239 extension_ = LoadManifestUnchecked("permissions", 240 "web_request_all_host_permissions.json", 241 Manifest::INVALID_LOCATION, 242 Extension::NO_FLAGS, 243 kExtensionId, 244 &error); 245 ASSERT_TRUE(extension_.get()) << error; 246 extension2_ = LoadManifestUnchecked("permissions", 247 "web_request_all_host_permissions.json", 248 Manifest::INVALID_LOCATION, 249 Extension::NO_FLAGS, 250 kExtensionId2, 251 &error); 252 ASSERT_TRUE(extension2_.get()) << error; 253 extension_info_map_ = new ExtensionInfoMap; 254 ASSERT_TRUE(extension_info_map_.get()); 255 extension_info_map_->AddExtension(extension_.get(), 256 base::Time() + base::TimeDelta::FromDays(1), 257 false /*incognito_enabled*/); 258 extension_info_map_->AddExtension(extension2_.get(), 259 base::Time() + base::TimeDelta::FromDays(2), 260 false /*incognito_enabled*/); 261} 262 263 264TEST_F(WebRequestRulesRegistryTest, AddRulesImpl) { 265 scoped_refptr<TestWebRequestRulesRegistry> registry( 266 new TestWebRequestRulesRegistry(extension_info_map_)); 267 std::string error; 268 269 std::vector<linked_ptr<RulesRegistry::Rule> > rules; 270 rules.push_back(CreateRule1()); 271 rules.push_back(CreateRule2()); 272 273 error = registry->AddRules(kExtensionId, rules); 274 EXPECT_EQ("", error); 275 EXPECT_EQ(1, registry->num_clear_cache_calls()); 276 277 std::set<const WebRequestRule*> matches; 278 279 GURL http_url("http://www.example.com"); 280 net::TestURLRequestContext context; 281 net::TestURLRequest http_request( 282 http_url, net::DEFAULT_PRIORITY, NULL, &context); 283 WebRequestData request_data(&http_request, ON_BEFORE_REQUEST); 284 matches = registry->GetMatches(request_data); 285 EXPECT_EQ(2u, matches.size()); 286 287 std::set<WebRequestRule::GlobalRuleId> matches_ids; 288 for (std::set<const WebRequestRule*>::const_iterator it = matches.begin(); 289 it != matches.end(); ++it) 290 matches_ids.insert((*it)->id()); 291 EXPECT_TRUE(ContainsKey(matches_ids, std::make_pair(kExtensionId, kRuleId1))); 292 EXPECT_TRUE(ContainsKey(matches_ids, std::make_pair(kExtensionId, kRuleId2))); 293 294 GURL foobar_url("http://www.foobar.com"); 295 net::TestURLRequest foobar_request( 296 foobar_url, net::DEFAULT_PRIORITY, NULL, &context); 297 request_data.request = &foobar_request; 298 matches = registry->GetMatches(request_data); 299 EXPECT_EQ(1u, matches.size()); 300 WebRequestRule::GlobalRuleId expected_pair = 301 std::make_pair(kExtensionId, kRuleId2); 302 EXPECT_EQ(expected_pair, (*matches.begin())->id()); 303} 304 305TEST_F(WebRequestRulesRegistryTest, RemoveRulesImpl) { 306 scoped_refptr<TestWebRequestRulesRegistry> registry( 307 new TestWebRequestRulesRegistry(extension_info_map_)); 308 std::string error; 309 310 // Setup RulesRegistry to contain two rules. 311 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add; 312 rules_to_add.push_back(CreateRule1()); 313 rules_to_add.push_back(CreateRule2()); 314 error = registry->AddRules(kExtensionId, rules_to_add); 315 EXPECT_EQ("", error); 316 EXPECT_EQ(1, registry->num_clear_cache_calls()); 317 318 // Verify initial state. 319 std::vector<linked_ptr<RulesRegistry::Rule> > registered_rules; 320 registry->GetAllRules(kExtensionId, ®istered_rules); 321 EXPECT_EQ(2u, registered_rules.size()); 322 EXPECT_EQ(1u, registry->RulesWithoutTriggers()); 323 324 // Remove first rule. 325 std::vector<std::string> rules_to_remove; 326 rules_to_remove.push_back(kRuleId1); 327 error = registry->RemoveRules(kExtensionId, rules_to_remove); 328 EXPECT_EQ("", error); 329 EXPECT_EQ(2, registry->num_clear_cache_calls()); 330 331 // Verify that only one rule is left. 332 registered_rules.clear(); 333 registry->GetAllRules(kExtensionId, ®istered_rules); 334 EXPECT_EQ(1u, registered_rules.size()); 335 EXPECT_EQ(1u, registry->RulesWithoutTriggers()); 336 337 // Now rules_to_remove contains both rules, i.e. one that does not exist in 338 // the rules registry anymore. Effectively we only remove the second rule. 339 rules_to_remove.push_back(kRuleId2); 340 error = registry->RemoveRules(kExtensionId, rules_to_remove); 341 EXPECT_EQ("", error); 342 EXPECT_EQ(3, registry->num_clear_cache_calls()); 343 344 // Verify that everything is gone. 345 registered_rules.clear(); 346 registry->GetAllRules(kExtensionId, ®istered_rules); 347 EXPECT_EQ(0u, registered_rules.size()); 348 EXPECT_EQ(0u, registry->RulesWithoutTriggers()); 349 350 EXPECT_TRUE(registry->IsEmpty()); 351} 352 353TEST_F(WebRequestRulesRegistryTest, RemoveAllRulesImpl) { 354 scoped_refptr<TestWebRequestRulesRegistry> registry( 355 new TestWebRequestRulesRegistry(extension_info_map_)); 356 std::string error; 357 358 // Setup RulesRegistry to contain two rules, one for each extension. 359 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add(1); 360 rules_to_add[0] = CreateRule1(); 361 error = registry->AddRules(kExtensionId, rules_to_add); 362 EXPECT_EQ("", error); 363 EXPECT_EQ(1, registry->num_clear_cache_calls()); 364 365 rules_to_add[0] = CreateRule2(); 366 error = registry->AddRules(kExtensionId2, rules_to_add); 367 EXPECT_EQ("", error); 368 EXPECT_EQ(2, registry->num_clear_cache_calls()); 369 370 // Verify initial state. 371 std::vector<linked_ptr<RulesRegistry::Rule> > registered_rules; 372 registry->GetAllRules(kExtensionId, ®istered_rules); 373 EXPECT_EQ(1u, registered_rules.size()); 374 registered_rules.clear(); 375 registry->GetAllRules(kExtensionId2, ®istered_rules); 376 EXPECT_EQ(1u, registered_rules.size()); 377 378 // Remove rule of first extension. 379 error = registry->RemoveAllRules(kExtensionId); 380 EXPECT_EQ("", error); 381 EXPECT_EQ(3, registry->num_clear_cache_calls()); 382 383 // Verify that only the first rule is deleted. 384 registered_rules.clear(); 385 registry->GetAllRules(kExtensionId, ®istered_rules); 386 EXPECT_EQ(0u, registered_rules.size()); 387 registered_rules.clear(); 388 registry->GetAllRules(kExtensionId2, ®istered_rules); 389 EXPECT_EQ(1u, registered_rules.size()); 390 391 // Test removing rules if none exist. 392 error = registry->RemoveAllRules(kExtensionId); 393 EXPECT_EQ("", error); 394 EXPECT_EQ(4, registry->num_clear_cache_calls()); 395 396 // Remove rule from second extension. 397 error = registry->RemoveAllRules(kExtensionId2); 398 EXPECT_EQ("", error); 399 EXPECT_EQ(5, registry->num_clear_cache_calls()); 400 401 EXPECT_TRUE(registry->IsEmpty()); 402} 403 404// Test precedences between extensions. 405TEST_F(WebRequestRulesRegistryTest, Precedences) { 406 scoped_refptr<WebRequestRulesRegistry> registry( 407 new TestWebRequestRulesRegistry(extension_info_map_)); 408 std::string error; 409 410 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_1(1); 411 rules_to_add_1[0] = CreateRedirectRule("http://www.foo.com"); 412 error = registry->AddRules(kExtensionId, rules_to_add_1); 413 EXPECT_EQ("", error); 414 415 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_2(1); 416 rules_to_add_2[0] = CreateRedirectRule("http://www.bar.com"); 417 error = registry->AddRules(kExtensionId2, rules_to_add_2); 418 EXPECT_EQ("", error); 419 420 GURL url("http://www.google.com"); 421 net::TestURLRequestContext context; 422 net::TestURLRequest request(url, net::DEFAULT_PRIORITY, NULL, &context); 423 WebRequestData request_data(&request, ON_BEFORE_REQUEST); 424 std::list<LinkedPtrEventResponseDelta> deltas = 425 registry->CreateDeltas(NULL, request_data, false); 426 427 // The second extension is installed later and will win for this reason 428 // in conflict resolution. 429 ASSERT_EQ(2u, deltas.size()); 430 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder); 431 432 std::list<LinkedPtrEventResponseDelta>::iterator i = deltas.begin(); 433 LinkedPtrEventResponseDelta winner = *i++; 434 LinkedPtrEventResponseDelta loser = *i; 435 436 EXPECT_EQ(kExtensionId2, winner->extension_id); 437 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(2), 438 winner->extension_install_time); 439 EXPECT_EQ(GURL("http://www.bar.com"), winner->new_url); 440 441 EXPECT_EQ(kExtensionId, loser->extension_id); 442 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(1), 443 loser->extension_install_time); 444 EXPECT_EQ(GURL("http://www.foo.com"), loser->new_url); 445} 446 447// Test priorities of rules within one extension. 448TEST_F(WebRequestRulesRegistryTest, Priorities) { 449 scoped_refptr<WebRequestRulesRegistry> registry( 450 new TestWebRequestRulesRegistry(extension_info_map_)); 451 std::string error; 452 453 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_1(1); 454 rules_to_add_1[0] = CreateRedirectRule("http://www.foo.com"); 455 error = registry->AddRules(kExtensionId, rules_to_add_1); 456 EXPECT_EQ("", error); 457 458 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_2(1); 459 rules_to_add_2[0] = CreateRedirectRule("http://www.bar.com"); 460 error = registry->AddRules(kExtensionId2, rules_to_add_2); 461 EXPECT_EQ("", error); 462 463 std::vector<linked_ptr<RulesRegistry::Rule> > rules_to_add_3(1); 464 rules_to_add_3[0] = CreateIgnoreRule(); 465 error = registry->AddRules(kExtensionId, rules_to_add_3); 466 EXPECT_EQ("", error); 467 468 GURL url("http://www.google.com/index.html"); 469 net::TestURLRequestContext context; 470 net::TestURLRequest request(url, net::DEFAULT_PRIORITY, NULL, &context); 471 WebRequestData request_data(&request, ON_BEFORE_REQUEST); 472 std::list<LinkedPtrEventResponseDelta> deltas = 473 registry->CreateDeltas(NULL, request_data, false); 474 475 // The redirect by the first extension is ignored due to the ignore rule. 476 ASSERT_EQ(1u, deltas.size()); 477 LinkedPtrEventResponseDelta effective_rule = *(deltas.begin()); 478 479 EXPECT_EQ(kExtensionId2, effective_rule->extension_id); 480 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(2), 481 effective_rule->extension_install_time); 482 EXPECT_EQ(GURL("http://www.bar.com"), effective_rule->new_url); 483} 484 485// Test ignoring of rules by tag. 486TEST_F(WebRequestRulesRegistryTest, IgnoreRulesByTag) { 487 const char kRule1[] = 488 "{ \n" 489 " \"id\": \"rule1\", \n" 490 " \"tags\": [\"non_matching_tag\", \"ignore_tag\"], \n" 491 " \"conditions\": [ \n" 492 " { \n" 493 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" 494 " \"url\": {\"hostSuffix\": \"foo.com\"} \n" 495 " } \n" 496 " ], \n" 497 " \"actions\": [ \n" 498 " { \n" 499 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" 500 " \"redirectUrl\": \"http://bar.com\" \n" 501 " } \n" 502 " ], \n" 503 " \"priority\": 200 \n" 504 "} "; 505 506 const char kRule2[] = 507 "{ \n" 508 " \"id\": \"rule2\", \n" 509 " \"conditions\": [ \n" 510 " { \n" 511 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" 512 " \"url\": {\"pathPrefix\": \"/test\"} \n" 513 " } \n" 514 " ], \n" 515 " \"actions\": [ \n" 516 " { \n" 517 " \"instanceType\": \"declarativeWebRequest.IgnoreRules\", \n" 518 " \"hasTag\": \"ignore_tag\" \n" 519 " } \n" 520 " ], \n" 521 " \"priority\": 300 \n" 522 "} "; 523 524 scoped_ptr<Value> value1(base::JSONReader::Read(kRule1)); 525 ASSERT_TRUE(value1.get()); 526 scoped_ptr<Value> value2(base::JSONReader::Read(kRule2)); 527 ASSERT_TRUE(value2.get()); 528 529 std::vector<linked_ptr<RulesRegistry::Rule> > rules; 530 rules.push_back(make_linked_ptr(new RulesRegistry::Rule)); 531 rules.push_back(make_linked_ptr(new RulesRegistry::Rule)); 532 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value1, rules[0].get())); 533 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value2, rules[1].get())); 534 535 scoped_refptr<WebRequestRulesRegistry> registry( 536 new TestWebRequestRulesRegistry(extension_info_map_)); 537 std::string error = registry->AddRulesImpl(kExtensionId, rules); 538 EXPECT_EQ("", error); 539 EXPECT_FALSE(registry->IsEmpty()); 540 541 GURL url("http://www.foo.com/test"); 542 net::TestURLRequestContext context; 543 net::TestURLRequest request(url, net::DEFAULT_PRIORITY, NULL, &context); 544 WebRequestData request_data(&request, ON_BEFORE_REQUEST); 545 std::list<LinkedPtrEventResponseDelta> deltas = 546 registry->CreateDeltas(NULL, request_data, false); 547 548 // The redirect by the redirect rule is ignored due to the ignore rule. 549 std::set<const WebRequestRule*> matches = registry->GetMatches(request_data); 550 EXPECT_EQ(2u, matches.size()); 551 ASSERT_EQ(0u, deltas.size()); 552} 553 554// Test that rules failing IsFulfilled on their conditions are never returned by 555// GetMatches. 556TEST_F(WebRequestRulesRegistryTest, GetMatchesCheckFulfilled) { 557 scoped_refptr<TestWebRequestRulesRegistry> registry( 558 new TestWebRequestRulesRegistry(extension_info_map_)); 559 const std::string kMatchingUrlAttribute( 560 "\"url\": { \"pathContains\": \"\" }, \n"); 561 const std::string kNonMatchingNonUrlAttribute( 562 "\"resourceType\": [\"stylesheet\"], \n"); 563 const std::string kBothAttributes(kMatchingUrlAttribute + 564 kNonMatchingNonUrlAttribute); 565 std::string error; 566 std::vector<const std::string*> attributes; 567 std::vector<linked_ptr<RulesRegistry::Rule> > rules; 568 569 // Rules 1 and 2 have one condition, neither of them should fire. 570 attributes.push_back(&kNonMatchingNonUrlAttribute); 571 rules.push_back(CreateCancellingRule(kRuleId1, attributes)); 572 573 attributes.clear(); 574 attributes.push_back(&kBothAttributes); 575 rules.push_back(CreateCancellingRule(kRuleId2, attributes)); 576 577 // Rule 3 has two conditions, one with a matching URL attribute, and one 578 // with a non-matching non-URL attribute. 579 attributes.clear(); 580 attributes.push_back(&kMatchingUrlAttribute); 581 attributes.push_back(&kNonMatchingNonUrlAttribute); 582 rules.push_back(CreateCancellingRule(kRuleId3, attributes)); 583 584 error = registry->AddRules(kExtensionId, rules); 585 EXPECT_EQ("", error); 586 EXPECT_EQ(1, registry->num_clear_cache_calls()); 587 588 std::set<const WebRequestRule*> matches; 589 590 GURL http_url("http://www.example.com"); 591 net::TestURLRequestContext context; 592 net::TestURLRequest http_request( 593 http_url, net::DEFAULT_PRIORITY, NULL, &context); 594 WebRequestData request_data(&http_request, ON_BEFORE_REQUEST); 595 matches = registry->GetMatches(request_data); 596 EXPECT_EQ(1u, matches.size()); 597 WebRequestRule::GlobalRuleId expected_pair = std::make_pair(kExtensionId, 598 kRuleId3); 599 EXPECT_EQ(expected_pair, (*matches.begin())->id()); 600} 601 602// Test that the url and firstPartyForCookiesUrl attributes are evaluated 603// against corresponding URLs. Tested on requests where these URLs actually 604// differ. 605TEST_F(WebRequestRulesRegistryTest, GetMatchesDifferentUrls) { 606 scoped_refptr<TestWebRequestRulesRegistry> registry( 607 new TestWebRequestRulesRegistry(extension_info_map_)); 608 const std::string kUrlAttribute( 609 "\"url\": { \"hostContains\": \"url\" }, \n"); 610 const std::string kFirstPartyUrlAttribute( 611 "\"firstPartyForCookiesUrl\": { \"hostContains\": \"fpfc\" }, \n"); 612 std::string error; 613 std::vector<const std::string*> attributes; 614 std::vector<linked_ptr<RulesRegistry::Rule> > rules; 615 616 // Rule 1 has one condition, with a url attribute 617 attributes.push_back(&kUrlAttribute); 618 rules.push_back(CreateCancellingRule(kRuleId1, attributes)); 619 620 // Rule 2 has one condition, with a firstPartyForCookiesUrl attribute 621 attributes.clear(); 622 attributes.push_back(&kFirstPartyUrlAttribute); 623 rules.push_back(CreateCancellingRule(kRuleId2, attributes)); 624 625 error = registry->AddRules(kExtensionId, rules); 626 EXPECT_EQ("", error); 627 EXPECT_EQ(1, registry->num_clear_cache_calls()); 628 629 std::set<const WebRequestRule*> matches; 630 631 const GURL urls[] = { 632 GURL("http://url.example.com"), // matching 633 GURL("http://www.example.com") // non-matching 634 }; 635 const GURL firstPartyUrls[] = { 636 GURL("http://www.example.com"), // non-matching 637 GURL("http://fpfc.example.com") // matching 638 }; 639 // Which rules should match in subsequent test iterations. 640 const char* matchingRuleIds[] = { kRuleId1, kRuleId2 }; 641 COMPILE_ASSERT(arraysize(urls) == arraysize(firstPartyUrls), 642 urls_and_firstPartyUrls_need_to_have_the_same_size); 643 COMPILE_ASSERT(arraysize(urls) == arraysize(matchingRuleIds), 644 urls_and_matchingRuleIds_need_to_have_the_same_size); 645 net::TestURLRequestContext context; 646 647 for (size_t i = 0; i < arraysize(matchingRuleIds); ++i) { 648 // Construct the inputs. 649 net::TestURLRequest http_request( 650 urls[i], net::DEFAULT_PRIORITY, NULL, &context); 651 WebRequestData request_data(&http_request, ON_BEFORE_REQUEST); 652 http_request.set_first_party_for_cookies(firstPartyUrls[i]); 653 // Now run both rules on the input. 654 matches = registry->GetMatches(request_data); 655 SCOPED_TRACE(testing::Message("i = ") << i << ", rule id = " 656 << matchingRuleIds[i]); 657 // Make sure that the right rule succeeded. 658 EXPECT_EQ(1u, matches.size()); 659 EXPECT_EQ(WebRequestRule::GlobalRuleId(std::make_pair(kExtensionId, 660 matchingRuleIds[i])), 661 (*matches.begin())->id()); 662 } 663} 664 665TEST(WebRequestRulesRegistrySimpleTest, StageChecker) { 666 // The contentType condition can only be evaluated during ON_HEADERS_RECEIVED 667 // but the redirect action can only be executed during ON_BEFORE_REQUEST. 668 // Therefore, this is an inconsistent rule that needs to be flagged. 669 const char kRule[] = 670 "{ \n" 671 " \"id\": \"rule1\", \n" 672 " \"conditions\": [ \n" 673 " { \n" 674 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" 675 " \"url\": {\"hostSuffix\": \"foo.com\"}, \n" 676 " \"contentType\": [\"image/jpeg\"] \n" 677 " } \n" 678 " ], \n" 679 " \"actions\": [ \n" 680 " { \n" 681 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" 682 " \"redirectUrl\": \"http://bar.com\" \n" 683 " } \n" 684 " ], \n" 685 " \"priority\": 200 \n" 686 "} "; 687 688 scoped_ptr<Value> value(base::JSONReader::Read(kRule)); 689 ASSERT_TRUE(value); 690 691 RulesRegistry::Rule rule; 692 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, &rule)); 693 694 std::string error; 695 URLMatcher matcher; 696 scoped_ptr<WebRequestConditionSet> conditions = 697 WebRequestConditionSet::Create( 698 NULL, matcher.condition_factory(), rule.conditions, &error); 699 ASSERT_TRUE(error.empty()) << error; 700 ASSERT_TRUE(conditions); 701 702 bool bad_message = false; 703 scoped_ptr<WebRequestActionSet> actions = 704 WebRequestActionSet::Create(NULL, rule.actions, &error, &bad_message); 705 ASSERT_TRUE(error.empty()) << error; 706 ASSERT_FALSE(bad_message); 707 ASSERT_TRUE(actions); 708 709 EXPECT_FALSE(WebRequestRulesRegistry::StageChecker( 710 conditions.get(), actions.get(), &error)); 711 EXPECT_THAT(error, HasSubstr("no time in the request life-cycle")); 712 EXPECT_THAT(error, HasSubstr(actions->actions().back()->GetName())); 713} 714 715TEST(WebRequestRulesRegistrySimpleTest, HostPermissionsChecker) { 716 const char kAction[] = // This action requires all URLs host permission. 717 "{ \n" 718 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" 719 " \"redirectUrl\": \"http://bar.com\" \n" 720 "} "; 721 scoped_ptr<Value> action_value(base::JSONReader::Read(kAction)); 722 ASSERT_TRUE(action_value); 723 724 WebRequestActionSet::AnyVector actions; 725 actions.push_back(linked_ptr<base::Value>(action_value.release())); 726 ASSERT_TRUE(actions.back().get()); 727 728 std::string error; 729 bool bad_message = false; 730 scoped_ptr<WebRequestActionSet> action_set( 731 WebRequestActionSet::Create(NULL, actions, &error, &bad_message)); 732 ASSERT_TRUE(error.empty()) << error; 733 ASSERT_FALSE(bad_message); 734 ASSERT_TRUE(action_set); 735 736 scoped_refptr<Extension> extension_no_url( 737 LoadManifest("permissions", "web_request_no_host.json")); 738 scoped_refptr<Extension> extension_some_urls( 739 LoadManifest("permissions", "web_request_com_host_permissions.json")); 740 scoped_refptr<Extension> extension_all_urls( 741 LoadManifest("permissions", "web_request_all_host_permissions.json")); 742 743 EXPECT_TRUE(WebRequestRulesRegistry::HostPermissionsChecker( 744 extension_all_urls.get(), action_set.get(), &error)); 745 EXPECT_TRUE(error.empty()) << error; 746 747 EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker( 748 extension_some_urls.get(), action_set.get(), &error)); 749 EXPECT_THAT(error, HasSubstr("permission for all")); 750 EXPECT_THAT(error, HasSubstr(action_set->actions().back()->GetName())); 751 752 EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker( 753 extension_no_url.get(), action_set.get(), &error)); 754 EXPECT_THAT(error, HasSubstr("permission for all")); 755 EXPECT_THAT(error, HasSubstr(action_set->actions().back()->GetName())); 756} 757 758TEST_F(WebRequestRulesRegistryTest, CheckOriginAndPathRegEx) { 759 const char kRule[] = 760 "{ \n" 761 " \"id\": \"rule1\", \n" 762 " \"conditions\": [ \n" 763 " { \n" 764 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n" 765 " \"url\": {\"originAndPathMatches\": \"fo+.com\"} \n" 766 " } \n" 767 " ], \n" 768 " \"actions\": [ \n" 769 " { \n" 770 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n" 771 " \"redirectUrl\": \"http://bar.com\" \n" 772 " } \n" 773 " ], \n" 774 " \"priority\": 200 \n" 775 "} "; 776 777 scoped_ptr<Value> value(base::JSONReader::Read(kRule)); 778 ASSERT_TRUE(value.get()); 779 780 std::vector<linked_ptr<RulesRegistry::Rule> > rules; 781 rules.push_back(make_linked_ptr(new RulesRegistry::Rule)); 782 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, rules.back().get())); 783 784 scoped_refptr<WebRequestRulesRegistry> registry( 785 new TestWebRequestRulesRegistry(extension_info_map_)); 786 787 URLMatcher matcher; 788 std::string error = registry->AddRulesImpl(kExtensionId, rules); 789 EXPECT_EQ("", error); 790 791 net::TestURLRequestContext context; 792 std::list<LinkedPtrEventResponseDelta> deltas; 793 794 // No match because match is in the query parameter. 795 GURL url1("http://bar.com/index.html?foo.com"); 796 net::TestURLRequest request1(url1, net::DEFAULT_PRIORITY, NULL, &context); 797 WebRequestData request_data1(&request1, ON_BEFORE_REQUEST); 798 deltas = registry->CreateDeltas(NULL, request_data1, false); 799 EXPECT_EQ(0u, deltas.size()); 800 801 // This is a correct match. 802 GURL url2("http://foo.com/index.html"); 803 net::TestURLRequest request2(url2, net::DEFAULT_PRIORITY, NULL, &context); 804 WebRequestData request_data2(&request2, ON_BEFORE_REQUEST); 805 deltas = registry->CreateDeltas(NULL, request_data2, false); 806 EXPECT_EQ(1u, deltas.size()); 807} 808 809} // namespace extensions 810