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_action.h" 6 7 #include "base/files/file_path.h" 8 #include "base/json/json_file_value_serializer.h" 9 #include "base/memory/ref_counted.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/path_service.h" 13 #include "base/test/values_test_util.h" 14 #include "base/time/time.h" 15 #include "base/values.h" 16 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" 17 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" 18 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" 19 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 20 #include "chrome/common/chrome_paths.h" 21 #include "chrome/common/extensions/extension_constants.h" 22 #include "chrome/common/extensions/extension_test_util.h" 23 #include "content/public/test/test_browser_thread_bundle.h" 24 #include "extensions/browser/info_map.h" 25 #include "extensions/common/extension.h" 26 #include "net/base/request_priority.h" 27 #include "net/http/http_response_headers.h" 28 #include "net/url_request/url_request_test_util.h" 29 #include "testing/gmock/include/gmock/gmock.h" 30 #include "testing/gtest/include/gtest/gtest.h" 31 32 using base::DictionaryValue; 33 using base::ListValue; 34 using extension_test_util::LoadManifestUnchecked; 35 using testing::HasSubstr; 36 37 namespace extensions { 38 39 namespace { 40 41 const char kUnknownActionType[] = "unknownType"; 42 43 scoped_ptr<WebRequestActionSet> CreateSetOfActions(const char* json) { 44 scoped_ptr<base::Value> parsed_value(base::test::ParseJson(json)); 45 const base::ListValue* parsed_list; 46 CHECK(parsed_value->GetAsList(&parsed_list)); 47 48 WebRequestActionSet::AnyVector actions; 49 for (base::ListValue::const_iterator it = parsed_list->begin(); 50 it != parsed_list->end(); 51 ++it) { 52 const base::DictionaryValue* dict; 53 CHECK((*it)->GetAsDictionary(&dict)); 54 actions.push_back(linked_ptr<base::Value>(dict->DeepCopy())); 55 } 56 57 std::string error; 58 bool bad_message = false; 59 60 scoped_ptr<WebRequestActionSet> action_set( 61 WebRequestActionSet::Create(NULL, actions, &error, &bad_message)); 62 EXPECT_EQ("", error); 63 EXPECT_FALSE(bad_message); 64 CHECK(action_set); 65 return action_set.Pass(); 66 } 67 68 } // namespace 69 70 namespace keys = declarative_webrequest_constants; 71 72 class WebRequestActionWithThreadsTest : public testing::Test { 73 public: 74 WebRequestActionWithThreadsTest() 75 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} 76 77 protected: 78 virtual void SetUp() OVERRIDE; 79 80 // Creates a URL request for URL |url_string|, and applies the actions from 81 // |action_set| as if they were triggered by the extension with 82 // |extension_id| during |stage|. 83 bool ActionWorksOnRequest(const char* url_string, 84 const std::string& extension_id, 85 const WebRequestActionSet* action_set, 86 RequestStage stage); 87 88 // Expects a JSON description of an |action| requiring <all_urls> host 89 // permission, and checks that only an extensions with full host permissions 90 // can execute that action at |stage|. Also checks that the action is not 91 // executable for http://clients1.google.com. 92 void CheckActionNeedsAllUrls(const char* action, RequestStage stage); 93 94 net::TestURLRequestContext context_; 95 96 // An extension with *.com host permissions and the DWR permission. 97 scoped_refptr<Extension> extension_; 98 // An extension with host permissions for all URLs and the DWR permission. 99 scoped_refptr<Extension> extension_all_urls_; 100 scoped_refptr<InfoMap> extension_info_map_; 101 102 private: 103 content::TestBrowserThreadBundle thread_bundle_; 104 }; 105 106 void WebRequestActionWithThreadsTest::SetUp() { 107 testing::Test::SetUp(); 108 109 std::string error; 110 extension_ = LoadManifestUnchecked("permissions", 111 "web_request_com_host_permissions.json", 112 Manifest::INVALID_LOCATION, 113 Extension::NO_FLAGS, 114 "ext_id_1", 115 &error); 116 ASSERT_TRUE(extension_.get()) << error; 117 extension_all_urls_ = 118 LoadManifestUnchecked("permissions", 119 "web_request_all_host_permissions.json", 120 Manifest::INVALID_LOCATION, 121 Extension::NO_FLAGS, 122 "ext_id_2", 123 &error); 124 ASSERT_TRUE(extension_all_urls_.get()) << error; 125 extension_info_map_ = new InfoMap; 126 ASSERT_TRUE(extension_info_map_.get()); 127 extension_info_map_->AddExtension( 128 extension_.get(), 129 base::Time::Now(), 130 false /*incognito_enabled*/, 131 false /*notifications_disabled*/); 132 extension_info_map_->AddExtension(extension_all_urls_.get(), 133 base::Time::Now(), 134 false /*incognito_enabled*/, 135 false /*notifications_disabled*/); 136 } 137 138 bool WebRequestActionWithThreadsTest::ActionWorksOnRequest( 139 const char* url_string, 140 const std::string& extension_id, 141 const WebRequestActionSet* action_set, 142 RequestStage stage) { 143 net::TestURLRequest regular_request( 144 GURL(url_string), net::DEFAULT_PRIORITY, NULL, &context_); 145 std::list<LinkedPtrEventResponseDelta> deltas; 146 scoped_refptr<net::HttpResponseHeaders> headers( 147 new net::HttpResponseHeaders("")); 148 WebRequestData request_data(®ular_request, stage, headers.get()); 149 std::set<std::string> ignored_tags; 150 WebRequestAction::ApplyInfo apply_info = { extension_info_map_.get(), 151 request_data, 152 false /*crosses_incognito*/, 153 &deltas, &ignored_tags }; 154 action_set->Apply(extension_id, base::Time(), &apply_info); 155 return (1u == deltas.size() || 0u < ignored_tags.size()); 156 } 157 158 void WebRequestActionWithThreadsTest::CheckActionNeedsAllUrls( 159 const char* action, 160 RequestStage stage) { 161 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(action)); 162 163 // Although |extension_| has matching *.com host permission, |action| 164 // is intentionally forbidden -- in Declarative WR, host permission 165 // for less than all URLs are ignored (except in SendMessageToExtension). 166 EXPECT_FALSE(ActionWorksOnRequest( 167 "http://test.com", extension_->id(), action_set.get(), stage)); 168 // With the "<all_urls>" host permission they are allowed. 169 EXPECT_TRUE(ActionWorksOnRequest( 170 "http://test.com", extension_all_urls_->id(), action_set.get(), stage)); 171 172 // The protected URLs should not be touched at all. 173 EXPECT_FALSE(ActionWorksOnRequest( 174 "http://clients1.google.com", extension_->id(), action_set.get(), stage)); 175 EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com", 176 extension_all_urls_->id(), 177 action_set.get(), 178 stage)); 179 } 180 181 TEST(WebRequestActionTest, CreateAction) { 182 std::string error; 183 bool bad_message = false; 184 scoped_refptr<const WebRequestAction> result; 185 186 // Test wrong data type passed. 187 error.clear(); 188 base::ListValue empty_list; 189 result = WebRequestAction::Create(NULL, empty_list, &error, &bad_message); 190 EXPECT_TRUE(bad_message); 191 EXPECT_FALSE(result.get()); 192 193 // Test missing instanceType element. 194 base::DictionaryValue input; 195 error.clear(); 196 result = WebRequestAction::Create(NULL, input, &error, &bad_message); 197 EXPECT_TRUE(bad_message); 198 EXPECT_FALSE(result.get()); 199 200 // Test wrong instanceType element. 201 input.SetString(keys::kInstanceTypeKey, kUnknownActionType); 202 error.clear(); 203 result = WebRequestAction::Create(NULL, input, &error, &bad_message); 204 EXPECT_NE("", error); 205 EXPECT_FALSE(result.get()); 206 207 // Test success 208 input.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType); 209 error.clear(); 210 result = WebRequestAction::Create(NULL, input, &error, &bad_message); 211 EXPECT_EQ("", error); 212 EXPECT_FALSE(bad_message); 213 ASSERT_TRUE(result.get()); 214 EXPECT_EQ(WebRequestAction::ACTION_CANCEL_REQUEST, result->type()); 215 } 216 217 TEST(WebRequestActionTest, CreateActionSet) { 218 std::string error; 219 bool bad_message = false; 220 scoped_ptr<WebRequestActionSet> result; 221 222 WebRequestActionSet::AnyVector input; 223 224 // Test empty input. 225 error.clear(); 226 result = WebRequestActionSet::Create(NULL, input, &error, &bad_message); 227 EXPECT_TRUE(error.empty()) << error; 228 EXPECT_FALSE(bad_message); 229 ASSERT_TRUE(result.get()); 230 EXPECT_TRUE(result->actions().empty()); 231 EXPECT_EQ(std::numeric_limits<int>::min(), result->GetMinimumPriority()); 232 233 base::DictionaryValue correct_action; 234 correct_action.SetString(keys::kInstanceTypeKey, keys::kIgnoreRulesType); 235 correct_action.SetInteger(keys::kLowerPriorityThanKey, 10); 236 base::DictionaryValue incorrect_action; 237 incorrect_action.SetString(keys::kInstanceTypeKey, kUnknownActionType); 238 239 // Test success. 240 input.push_back(linked_ptr<base::Value>(correct_action.DeepCopy())); 241 error.clear(); 242 result = WebRequestActionSet::Create(NULL, input, &error, &bad_message); 243 EXPECT_TRUE(error.empty()) << error; 244 EXPECT_FALSE(bad_message); 245 ASSERT_TRUE(result.get()); 246 ASSERT_EQ(1u, result->actions().size()); 247 EXPECT_EQ(WebRequestAction::ACTION_IGNORE_RULES, 248 result->actions()[0]->type()); 249 EXPECT_EQ(10, result->GetMinimumPriority()); 250 251 // Test failure. 252 input.push_back(linked_ptr<base::Value>(incorrect_action.DeepCopy())); 253 error.clear(); 254 result = WebRequestActionSet::Create(NULL, input, &error, &bad_message); 255 EXPECT_NE("", error); 256 EXPECT_FALSE(result.get()); 257 } 258 259 // Test capture group syntax conversions of WebRequestRedirectByRegExAction 260 TEST(WebRequestActionTest, PerlToRe2Style) { 261 #define CallPerlToRe2Style WebRequestRedirectByRegExAction::PerlToRe2Style 262 // foo$1bar -> foo\1bar 263 EXPECT_EQ("foo\\1bar", CallPerlToRe2Style("foo$1bar")); 264 // foo\$1bar -> foo$1bar 265 EXPECT_EQ("foo$1bar", CallPerlToRe2Style("foo\\$1bar")); 266 // foo\\$1bar -> foo\\\1bar 267 EXPECT_EQ("foo\\\\\\1bar", CallPerlToRe2Style("foo\\\\$1bar")); 268 // foo\bar -> foobar 269 EXPECT_EQ("foobar", CallPerlToRe2Style("foo\\bar")); 270 // foo$bar -> foo$bar 271 EXPECT_EQ("foo$bar", CallPerlToRe2Style("foo$bar")); 272 #undef CallPerlToRe2Style 273 } 274 275 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirect) { 276 const char kAction[] = 277 "[{" 278 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\"," 279 " \"redirectUrl\": \"http://www.foobar.com\"" 280 "}]"; 281 CheckActionNeedsAllUrls(kAction, ON_BEFORE_REQUEST); 282 CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); 283 } 284 285 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirectByRegEx) { 286 const char kAction[] = 287 "[{" 288 " \"instanceType\": \"declarativeWebRequest.RedirectByRegEx\"," 289 " \"from\": \".*\"," 290 " \"to\": \"http://www.foobar.com\"" 291 "}]"; 292 CheckActionNeedsAllUrls(kAction, ON_BEFORE_REQUEST); 293 } 294 295 TEST_F(WebRequestActionWithThreadsTest, PermissionsToSetRequestHeader) { 296 const char kAction[] = 297 "[{" 298 " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\"," 299 " \"name\": \"testname\"," 300 " \"value\": \"testvalue\"" 301 "}]"; 302 CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); 303 } 304 305 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveRequestHeader) { 306 const char kAction[] = 307 "[{" 308 " \"instanceType\": \"declarativeWebRequest.RemoveRequestHeader\"," 309 " \"name\": \"testname\"" 310 "}]"; 311 CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); 312 } 313 314 TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddResponseHeader) { 315 const char kAction[] = 316 "[{" 317 " \"instanceType\": \"declarativeWebRequest.AddResponseHeader\"," 318 " \"name\": \"testname\"," 319 " \"value\": \"testvalue\"" 320 "}]"; 321 CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); 322 } 323 324 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveResponseHeader) { 325 const char kAction[] = 326 "[{" 327 " \"instanceType\": \"declarativeWebRequest.RemoveResponseHeader\"," 328 " \"name\": \"testname\"" 329 "}]"; 330 CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); 331 } 332 333 TEST_F(WebRequestActionWithThreadsTest, PermissionsToSendMessageToExtension) { 334 const char kAction[] = 335 "[{" 336 " \"instanceType\": \"declarativeWebRequest.SendMessageToExtension\"," 337 " \"message\": \"testtext\"" 338 "}]"; 339 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); 340 341 // For sending messages, specific host permissions actually matter. 342 EXPECT_TRUE(ActionWorksOnRequest("http://test.com", 343 extension_->id(), 344 action_set.get(), 345 ON_BEFORE_REQUEST)); 346 // With the "<all_urls>" host permission they are allowed. 347 EXPECT_TRUE(ActionWorksOnRequest("http://test.com", 348 extension_all_urls_->id(), 349 action_set.get(), 350 ON_BEFORE_REQUEST)); 351 352 // The protected URLs should not be touched at all. 353 EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com", 354 extension_->id(), 355 action_set.get(), 356 ON_BEFORE_REQUEST)); 357 EXPECT_FALSE(ActionWorksOnRequest("http://clients1.google.com", 358 extension_all_urls_->id(), 359 action_set.get(), 360 ON_BEFORE_REQUEST)); 361 } 362 363 TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddRequestCookie) { 364 const char kAction[] = 365 "[{" 366 " \"instanceType\": \"declarativeWebRequest.AddRequestCookie\"," 367 " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 368 "}]"; 369 CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); 370 } 371 372 TEST_F(WebRequestActionWithThreadsTest, PermissionsToAddResponseCookie) { 373 const char kAction[] = 374 "[{" 375 " \"instanceType\": \"declarativeWebRequest.AddResponseCookie\"," 376 " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 377 "}]"; 378 CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); 379 } 380 381 TEST_F(WebRequestActionWithThreadsTest, PermissionsToEditRequestCookie) { 382 const char kAction[] = 383 "[{" 384 " \"instanceType\": \"declarativeWebRequest.EditRequestCookie\"," 385 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," 386 " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" 387 "}]"; 388 CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); 389 } 390 391 TEST_F(WebRequestActionWithThreadsTest, PermissionsToEditResponseCookie) { 392 const char kAction[] = 393 "[{" 394 " \"instanceType\": \"declarativeWebRequest.EditResponseCookie\"," 395 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," 396 " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" 397 "}]"; 398 CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); 399 } 400 401 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveRequestCookie) { 402 const char kAction[] = 403 "[{" 404 " \"instanceType\": \"declarativeWebRequest.RemoveRequestCookie\"," 405 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 406 "}]"; 407 CheckActionNeedsAllUrls(kAction, ON_BEFORE_SEND_HEADERS); 408 } 409 410 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRemoveResponseCookie) { 411 const char kAction[] = 412 "[{" 413 " \"instanceType\": \"declarativeWebRequest.RemoveResponseCookie\"," 414 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 415 "}]"; 416 CheckActionNeedsAllUrls(kAction, ON_HEADERS_RECEIVED); 417 } 418 419 TEST_F(WebRequestActionWithThreadsTest, PermissionsToCancel) { 420 const char kAction[] = 421 "[{" 422 " \"instanceType\": \"declarativeWebRequest.CancelRequest\"" 423 "}]"; 424 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); 425 426 // Cancelling requests works without full host permissions. 427 EXPECT_TRUE(ActionWorksOnRequest("http://test.org", 428 extension_->id(), 429 action_set.get(), 430 ON_BEFORE_REQUEST)); 431 } 432 433 TEST_F(WebRequestActionWithThreadsTest, 434 PermissionsToRedirectToTransparentImage) { 435 const char kAction[] = 436 "[{" 437 " \"instanceType\": \"declarativeWebRequest.RedirectToTransparentImage\"" 438 "}]"; 439 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); 440 441 // Redirecting to transparent images works without full host permissions. 442 EXPECT_TRUE(ActionWorksOnRequest("http://test.org", 443 extension_->id(), 444 action_set.get(), 445 ON_BEFORE_REQUEST)); 446 EXPECT_TRUE(ActionWorksOnRequest("http://test.org", 447 extension_->id(), 448 action_set.get(), 449 ON_HEADERS_RECEIVED)); 450 } 451 452 TEST_F(WebRequestActionWithThreadsTest, PermissionsToRedirectToEmptyDocument) { 453 const char kAction[] = 454 "[{" 455 " \"instanceType\": \"declarativeWebRequest.RedirectToEmptyDocument\"" 456 "}]"; 457 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); 458 459 // Redirecting to the empty document works without full host permissions. 460 EXPECT_TRUE(ActionWorksOnRequest("http://test.org", 461 extension_->id(), 462 action_set.get(), 463 ON_BEFORE_REQUEST)); 464 EXPECT_TRUE(ActionWorksOnRequest("http://test.org", 465 extension_->id(), 466 action_set.get(), 467 ON_HEADERS_RECEIVED)); 468 } 469 470 TEST_F(WebRequestActionWithThreadsTest, PermissionsToIgnore) { 471 const char kAction[] = 472 "[{" 473 " \"instanceType\": \"declarativeWebRequest.IgnoreRules\"," 474 " \"lowerPriorityThan\": 123," 475 " \"hasTag\": \"some_tag\"" 476 "}]"; 477 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kAction)); 478 479 // Ignoring rules works without full host permissions. 480 EXPECT_TRUE(ActionWorksOnRequest("http://test.org", 481 extension_->id(), 482 action_set.get(), 483 ON_BEFORE_REQUEST)); 484 } 485 486 TEST(WebRequestActionTest, GetName) { 487 const char kActions[] = 488 "[{" 489 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\"," 490 " \"redirectUrl\": \"http://www.foobar.com\"" 491 "}," 492 "{" 493 " \"instanceType\": \"declarativeWebRequest.RedirectByRegEx\"," 494 " \"from\": \".*\"," 495 " \"to\": \"http://www.foobar.com\"" 496 "}," 497 "{" 498 " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\"," 499 " \"name\": \"testname\"," 500 " \"value\": \"testvalue\"" 501 "}," 502 "{" 503 " \"instanceType\": \"declarativeWebRequest.RemoveRequestHeader\"," 504 " \"name\": \"testname\"" 505 "}," 506 "{" 507 " \"instanceType\": \"declarativeWebRequest.AddResponseHeader\"," 508 " \"name\": \"testname\"," 509 " \"value\": \"testvalue\"" 510 "}," 511 "{" 512 " \"instanceType\": \"declarativeWebRequest.RemoveResponseHeader\"," 513 " \"name\": \"testname\"" 514 "}," 515 "{" 516 " \"instanceType\": \"declarativeWebRequest.SendMessageToExtension\"," 517 " \"message\": \"testtext\"" 518 "}," 519 "{" 520 " \"instanceType\": \"declarativeWebRequest.AddRequestCookie\"," 521 " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 522 "}," 523 "{" 524 " \"instanceType\": \"declarativeWebRequest.AddResponseCookie\"," 525 " \"cookie\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 526 "}," 527 "{" 528 " \"instanceType\": \"declarativeWebRequest.EditRequestCookie\"," 529 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," 530 " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" 531 "}," 532 "{" 533 " \"instanceType\": \"declarativeWebRequest.EditResponseCookie\"," 534 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }," 535 " \"modification\": { \"name\": \"name2\", \"value\": \"value2\" }" 536 "}," 537 "{" 538 " \"instanceType\": \"declarativeWebRequest.RemoveRequestCookie\"," 539 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 540 "}," 541 "{" 542 " \"instanceType\": \"declarativeWebRequest.RemoveResponseCookie\"," 543 " \"filter\": { \"name\": \"cookiename\", \"value\": \"cookievalue\" }" 544 "}," 545 "{" 546 " \"instanceType\": \"declarativeWebRequest.CancelRequest\"" 547 "}," 548 "{" 549 " \"instanceType\": \"declarativeWebRequest.RedirectToTransparentImage\"" 550 "}," 551 "{" 552 " \"instanceType\": \"declarativeWebRequest.RedirectToEmptyDocument\"" 553 "}," 554 "{" 555 " \"instanceType\": \"declarativeWebRequest.IgnoreRules\"," 556 " \"lowerPriorityThan\": 123," 557 " \"hasTag\": \"some_tag\"" 558 "}]"; 559 const char* kExpectedNames[] = { 560 "declarativeWebRequest.RedirectRequest", 561 "declarativeWebRequest.RedirectByRegEx", 562 "declarativeWebRequest.SetRequestHeader", 563 "declarativeWebRequest.RemoveRequestHeader", 564 "declarativeWebRequest.AddResponseHeader", 565 "declarativeWebRequest.RemoveResponseHeader", 566 "declarativeWebRequest.SendMessageToExtension", 567 "declarativeWebRequest.AddRequestCookie", 568 "declarativeWebRequest.AddResponseCookie", 569 "declarativeWebRequest.EditRequestCookie", 570 "declarativeWebRequest.EditResponseCookie", 571 "declarativeWebRequest.RemoveRequestCookie", 572 "declarativeWebRequest.RemoveResponseCookie", 573 "declarativeWebRequest.CancelRequest", 574 "declarativeWebRequest.RedirectToTransparentImage", 575 "declarativeWebRequest.RedirectToEmptyDocument", 576 "declarativeWebRequest.IgnoreRules", 577 }; 578 scoped_ptr<WebRequestActionSet> action_set(CreateSetOfActions(kActions)); 579 ASSERT_EQ(arraysize(kExpectedNames), action_set->actions().size()); 580 size_t index = 0; 581 for (WebRequestActionSet::Actions::const_iterator it = 582 action_set->actions().begin(); 583 it != action_set->actions().end(); 584 ++it) { 585 EXPECT_EQ(kExpectedNames[index], (*it)->GetName()); 586 ++index; 587 } 588 } 589 590 } // namespace extensions 591