Home | History | Annotate | Download | only in declarative_webrequest
      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(&regular_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