• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CreateSetOfActions(const char * json)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:
WebRequestActionWithThreadsTest()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 
SetUp()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 
ActionWorksOnRequest(const char * url_string,const std::string & extension_id,const WebRequestActionSet * action_set,RequestStage stage)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 
CheckActionNeedsAllUrls(const char * action,RequestStage stage)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 
TEST(WebRequestActionTest,CreateAction)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 
TEST(WebRequestActionTest,CreateActionSet)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
TEST(WebRequestActionTest,PerlToRe2Style)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRedirect)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRedirectByRegEx)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToSetRequestHeader)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRemoveRequestHeader)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToAddResponseHeader)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRemoveResponseHeader)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToSendMessageToExtension)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToAddRequestCookie)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToAddResponseCookie)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToEditRequestCookie)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToEditResponseCookie)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRemoveRequestCookie)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRemoveResponseCookie)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToCancel)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRedirectToTransparentImage)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToRedirectToEmptyDocument)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 
TEST_F(WebRequestActionWithThreadsTest,PermissionsToIgnore)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 
TEST(WebRequestActionTest,GetName)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