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