• 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 <limits>
8 
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/declarative/deduping_factory.h"
15 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
16 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"
17 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
18 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
19 #include "chrome/browser/extensions/api/web_request/web_request_permissions.h"
20 #include "content/public/common/url_constants.h"
21 #include "extensions/browser/info_map.h"
22 #include "extensions/common/extension.h"
23 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
24 #include "net/url_request/url_request.h"
25 #include "third_party/re2/re2/re2.h"
26 
27 namespace extensions {
28 
29 namespace helpers = extension_web_request_api_helpers;
30 namespace keys = declarative_webrequest_constants;
31 
32 namespace {
33 // Error messages.
34 const char kIgnoreRulesRequiresParameterError[] =
35     "IgnoreRules requires at least one parameter.";
36 
37 const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh"
38     "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==";
39 const char kEmptyDocumentUrl[] = "data:text/html,";
40 
41 #define INPUT_FORMAT_VALIDATE(test) do { \
42     if (!(test)) { \
43       *bad_message = true; \
44       return scoped_refptr<const WebRequestAction>(NULL); \
45     } \
46   } while (0)
47 
ParseRequestCookie(const base::DictionaryValue * dict)48 scoped_ptr<helpers::RequestCookie> ParseRequestCookie(
49     const base::DictionaryValue* dict) {
50   scoped_ptr<helpers::RequestCookie> result(new helpers::RequestCookie);
51   std::string tmp;
52   if (dict->GetString(keys::kNameKey, &tmp))
53     result->name.reset(new std::string(tmp));
54   if (dict->GetString(keys::kValueKey, &tmp))
55     result->value.reset(new std::string(tmp));
56   return result.Pass();
57 }
58 
ParseResponseCookieImpl(const base::DictionaryValue * dict,helpers::ResponseCookie * cookie)59 void ParseResponseCookieImpl(const base::DictionaryValue* dict,
60                              helpers::ResponseCookie* cookie) {
61   std::string string_tmp;
62   int int_tmp = 0;
63   bool bool_tmp = false;
64   if (dict->GetString(keys::kNameKey, &string_tmp))
65     cookie->name.reset(new std::string(string_tmp));
66   if (dict->GetString(keys::kValueKey, &string_tmp))
67     cookie->value.reset(new std::string(string_tmp));
68   if (dict->GetString(keys::kExpiresKey, &string_tmp))
69     cookie->expires.reset(new std::string(string_tmp));
70   if (dict->GetInteger(keys::kMaxAgeKey, &int_tmp))
71     cookie->max_age.reset(new int(int_tmp));
72   if (dict->GetString(keys::kDomainKey, &string_tmp))
73     cookie->domain.reset(new std::string(string_tmp));
74   if (dict->GetString(keys::kPathKey, &string_tmp))
75     cookie->path.reset(new std::string(string_tmp));
76   if (dict->GetBoolean(keys::kSecureKey, &bool_tmp))
77     cookie->secure.reset(new bool(bool_tmp));
78   if (dict->GetBoolean(keys::kHttpOnlyKey, &bool_tmp))
79     cookie->http_only.reset(new bool(bool_tmp));
80 }
81 
ParseResponseCookie(const base::DictionaryValue * dict)82 scoped_ptr<helpers::ResponseCookie> ParseResponseCookie(
83     const base::DictionaryValue* dict) {
84   scoped_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie);
85   ParseResponseCookieImpl(dict, result.get());
86   return result.Pass();
87 }
88 
ParseFilterResponseCookie(const base::DictionaryValue * dict)89 scoped_ptr<helpers::FilterResponseCookie> ParseFilterResponseCookie(
90     const base::DictionaryValue* dict) {
91   scoped_ptr<helpers::FilterResponseCookie> result(
92       new helpers::FilterResponseCookie);
93   ParseResponseCookieImpl(dict, result.get());
94 
95   int int_tmp = 0;
96   bool bool_tmp = false;
97   if (dict->GetInteger(keys::kAgeUpperBoundKey, &int_tmp))
98     result->age_upper_bound.reset(new int(int_tmp));
99   if (dict->GetInteger(keys::kAgeLowerBoundKey, &int_tmp))
100     result->age_lower_bound.reset(new int(int_tmp));
101   if (dict->GetBoolean(keys::kSessionCookieKey, &bool_tmp))
102     result->session_cookie.reset(new bool(bool_tmp));
103   return result.Pass();
104 }
105 
106 // Helper function for WebRequestActions that can be instantiated by just
107 // calling the constructor.
108 template <class T>
CallConstructorFactoryMethod(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)109 scoped_refptr<const WebRequestAction> CallConstructorFactoryMethod(
110     const std::string& instance_type,
111     const base::Value* value,
112     std::string* error,
113     bool* bad_message) {
114   return scoped_refptr<const WebRequestAction>(new T);
115 }
116 
CreateRedirectRequestAction(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)117 scoped_refptr<const WebRequestAction> CreateRedirectRequestAction(
118     const std::string& instance_type,
119     const base::Value* value,
120     std::string* error,
121     bool* bad_message) {
122   const base::DictionaryValue* dict = NULL;
123   CHECK(value->GetAsDictionary(&dict));
124   std::string redirect_url_string;
125   INPUT_FORMAT_VALIDATE(
126       dict->GetString(keys::kRedirectUrlKey, &redirect_url_string));
127   GURL redirect_url(redirect_url_string);
128   return scoped_refptr<const WebRequestAction>(
129       new WebRequestRedirectAction(redirect_url));
130 }
131 
CreateRedirectRequestByRegExAction(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)132 scoped_refptr<const WebRequestAction> CreateRedirectRequestByRegExAction(
133     const std::string& instance_type,
134     const base::Value* value,
135     std::string* error,
136     bool* bad_message) {
137   const base::DictionaryValue* dict = NULL;
138   CHECK(value->GetAsDictionary(&dict));
139   std::string from;
140   std::string to;
141   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from));
142   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to));
143 
144   to = WebRequestRedirectByRegExAction::PerlToRe2Style(to);
145 
146   RE2::Options options;
147   options.set_case_sensitive(false);
148   scoped_ptr<RE2> from_pattern(new RE2(from, options));
149 
150   if (!from_pattern->ok()) {
151     *error = "Invalid pattern '" + from + "' -> '" + to + "'";
152     return scoped_refptr<const WebRequestAction>(NULL);
153   }
154   return scoped_refptr<const WebRequestAction>(
155       new WebRequestRedirectByRegExAction(from_pattern.Pass(), to));
156 }
157 
CreateSetRequestHeaderAction(const std::string & instance_type,const base::Value * json_value,std::string * error,bool * bad_message)158 scoped_refptr<const WebRequestAction> CreateSetRequestHeaderAction(
159     const std::string& instance_type,
160     const base::Value* json_value,
161     std::string* error,
162     bool* bad_message) {
163   const base::DictionaryValue* dict = NULL;
164   CHECK(json_value->GetAsDictionary(&dict));
165   std::string name;
166   std::string value;
167   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
168   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
169   return scoped_refptr<const WebRequestAction>(
170       new WebRequestSetRequestHeaderAction(name, value));
171 }
172 
CreateRemoveRequestHeaderAction(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)173 scoped_refptr<const WebRequestAction> CreateRemoveRequestHeaderAction(
174     const std::string& instance_type,
175     const base::Value* value,
176     std::string* error,
177     bool* bad_message) {
178   const base::DictionaryValue* dict = NULL;
179   CHECK(value->GetAsDictionary(&dict));
180   std::string name;
181   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
182   return scoped_refptr<const WebRequestAction>(
183       new WebRequestRemoveRequestHeaderAction(name));
184 }
185 
CreateAddResponseHeaderAction(const std::string & instance_type,const base::Value * json_value,std::string * error,bool * bad_message)186 scoped_refptr<const WebRequestAction> CreateAddResponseHeaderAction(
187     const std::string& instance_type,
188     const base::Value* json_value,
189     std::string* error,
190     bool* bad_message) {
191   const base::DictionaryValue* dict = NULL;
192   CHECK(json_value->GetAsDictionary(&dict));
193   std::string name;
194   std::string value;
195   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
196   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
197   return scoped_refptr<const WebRequestAction>(
198       new WebRequestAddResponseHeaderAction(name, value));
199 }
200 
CreateRemoveResponseHeaderAction(const std::string & instance_type,const base::Value * json_value,std::string * error,bool * bad_message)201 scoped_refptr<const WebRequestAction> CreateRemoveResponseHeaderAction(
202     const std::string& instance_type,
203     const base::Value* json_value,
204     std::string* error,
205     bool* bad_message) {
206   const base::DictionaryValue* dict = NULL;
207   CHECK(json_value->GetAsDictionary(&dict));
208   std::string name;
209   std::string value;
210   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
211   bool has_value = dict->GetString(keys::kValueKey, &value);
212   return scoped_refptr<const WebRequestAction>(
213       new WebRequestRemoveResponseHeaderAction(name, value, has_value));
214 }
215 
CreateIgnoreRulesAction(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)216 scoped_refptr<const WebRequestAction> CreateIgnoreRulesAction(
217     const std::string& instance_type,
218     const base::Value* value,
219     std::string* error,
220     bool* bad_message) {
221   const base::DictionaryValue* dict = NULL;
222   CHECK(value->GetAsDictionary(&dict));
223   bool has_parameter = false;
224   int minimum_priority = std::numeric_limits<int>::min();
225   std::string ignore_tag;
226   if (dict->HasKey(keys::kLowerPriorityThanKey)) {
227     INPUT_FORMAT_VALIDATE(
228         dict->GetInteger(keys::kLowerPriorityThanKey, &minimum_priority));
229     has_parameter = true;
230   }
231   if (dict->HasKey(keys::kHasTagKey)) {
232     INPUT_FORMAT_VALIDATE(dict->GetString(keys::kHasTagKey, &ignore_tag));
233     has_parameter = true;
234   }
235   if (!has_parameter) {
236     *error = kIgnoreRulesRequiresParameterError;
237     return scoped_refptr<const WebRequestAction>(NULL);
238   }
239   return scoped_refptr<const WebRequestAction>(
240       new WebRequestIgnoreRulesAction(minimum_priority, ignore_tag));
241 }
242 
CreateRequestCookieAction(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)243 scoped_refptr<const WebRequestAction> CreateRequestCookieAction(
244     const std::string& instance_type,
245     const base::Value* value,
246     std::string* error,
247     bool* bad_message) {
248   using extension_web_request_api_helpers::RequestCookieModification;
249 
250   const base::DictionaryValue* dict = NULL;
251   CHECK(value->GetAsDictionary(&dict));
252 
253   linked_ptr<RequestCookieModification> modification(
254       new RequestCookieModification);
255 
256   // Get modification type.
257   if (instance_type == keys::kAddRequestCookieType)
258     modification->type = helpers::ADD;
259   else if (instance_type == keys::kEditRequestCookieType)
260     modification->type = helpers::EDIT;
261   else if (instance_type == keys::kRemoveRequestCookieType)
262     modification->type = helpers::REMOVE;
263   else
264     INPUT_FORMAT_VALIDATE(false);
265 
266   // Get filter.
267   if (modification->type == helpers::EDIT ||
268       modification->type == helpers::REMOVE) {
269     const base::DictionaryValue* filter = NULL;
270     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
271     modification->filter = ParseRequestCookie(filter);
272   }
273 
274   // Get new value.
275   if (modification->type == helpers::ADD) {
276     const base::DictionaryValue* value = NULL;
277     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
278     modification->modification = ParseRequestCookie(value);
279   } else if (modification->type == helpers::EDIT) {
280     const base::DictionaryValue* value = NULL;
281     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
282     modification->modification = ParseRequestCookie(value);
283   }
284 
285   return scoped_refptr<const WebRequestAction>(
286       new WebRequestRequestCookieAction(modification));
287 }
288 
CreateResponseCookieAction(const std::string & instance_type,const base::Value * value,std::string * error,bool * bad_message)289 scoped_refptr<const WebRequestAction> CreateResponseCookieAction(
290     const std::string& instance_type,
291     const base::Value* value,
292     std::string* error,
293     bool* bad_message) {
294   using extension_web_request_api_helpers::ResponseCookieModification;
295 
296   const base::DictionaryValue* dict = NULL;
297   CHECK(value->GetAsDictionary(&dict));
298 
299   linked_ptr<ResponseCookieModification> modification(
300       new ResponseCookieModification);
301 
302   // Get modification type.
303   if (instance_type == keys::kAddResponseCookieType)
304     modification->type = helpers::ADD;
305   else if (instance_type == keys::kEditResponseCookieType)
306     modification->type = helpers::EDIT;
307   else if (instance_type == keys::kRemoveResponseCookieType)
308     modification->type = helpers::REMOVE;
309   else
310     INPUT_FORMAT_VALIDATE(false);
311 
312   // Get filter.
313   if (modification->type == helpers::EDIT ||
314       modification->type == helpers::REMOVE) {
315     const base::DictionaryValue* filter = NULL;
316     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
317     modification->filter = ParseFilterResponseCookie(filter);
318   }
319 
320   // Get new value.
321   if (modification->type == helpers::ADD) {
322     const base::DictionaryValue* value = NULL;
323     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
324     modification->modification = ParseResponseCookie(value);
325   } else if (modification->type == helpers::EDIT) {
326     const base::DictionaryValue* value = NULL;
327     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
328     modification->modification = ParseResponseCookie(value);
329   }
330 
331   return scoped_refptr<const WebRequestAction>(
332       new WebRequestResponseCookieAction(modification));
333 }
334 
CreateSendMessageToExtensionAction(const std::string & name,const base::Value * value,std::string * error,bool * bad_message)335 scoped_refptr<const WebRequestAction> CreateSendMessageToExtensionAction(
336     const std::string& name,
337     const base::Value* value,
338     std::string* error,
339     bool* bad_message) {
340   const base::DictionaryValue* dict = NULL;
341   CHECK(value->GetAsDictionary(&dict));
342   std::string message;
343   INPUT_FORMAT_VALIDATE(dict->GetString(keys::kMessageKey, &message));
344   return scoped_refptr<const WebRequestAction>(
345       new WebRequestSendMessageToExtensionAction(message));
346 }
347 
348 struct WebRequestActionFactory {
349   DedupingFactory<WebRequestAction> factory;
350 
WebRequestActionFactoryextensions::__anon0580ff0e0111::WebRequestActionFactory351   WebRequestActionFactory() : factory(5) {
352     factory.RegisterFactoryMethod(
353         keys::kAddRequestCookieType,
354         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
355         &CreateRequestCookieAction);
356     factory.RegisterFactoryMethod(
357         keys::kAddResponseCookieType,
358         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
359         &CreateResponseCookieAction);
360     factory.RegisterFactoryMethod(
361         keys::kAddResponseHeaderType,
362         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
363         &CreateAddResponseHeaderAction);
364     factory.RegisterFactoryMethod(
365         keys::kCancelRequestType,
366         DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
367         &CallConstructorFactoryMethod<WebRequestCancelAction>);
368     factory.RegisterFactoryMethod(
369         keys::kEditRequestCookieType,
370         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
371         &CreateRequestCookieAction);
372     factory.RegisterFactoryMethod(
373         keys::kEditResponseCookieType,
374         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
375         &CreateResponseCookieAction);
376     factory.RegisterFactoryMethod(
377         keys::kRedirectByRegExType,
378         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
379         &CreateRedirectRequestByRegExAction);
380     factory.RegisterFactoryMethod(
381         keys::kRedirectRequestType,
382         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
383         &CreateRedirectRequestAction);
384     factory.RegisterFactoryMethod(
385         keys::kRedirectToTransparentImageType,
386         DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
387         &CallConstructorFactoryMethod<
388             WebRequestRedirectToTransparentImageAction>);
389     factory.RegisterFactoryMethod(
390         keys::kRedirectToEmptyDocumentType,
391         DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
392         &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>);
393     factory.RegisterFactoryMethod(
394         keys::kRemoveRequestCookieType,
395         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
396         &CreateRequestCookieAction);
397     factory.RegisterFactoryMethod(
398         keys::kRemoveResponseCookieType,
399         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
400         &CreateResponseCookieAction);
401     factory.RegisterFactoryMethod(
402         keys::kSetRequestHeaderType,
403         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
404         &CreateSetRequestHeaderAction);
405     factory.RegisterFactoryMethod(
406         keys::kRemoveRequestHeaderType,
407         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
408         &CreateRemoveRequestHeaderAction);
409     factory.RegisterFactoryMethod(
410         keys::kRemoveResponseHeaderType,
411         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
412         &CreateRemoveResponseHeaderAction);
413     factory.RegisterFactoryMethod(
414         keys::kIgnoreRulesType,
415         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
416         &CreateIgnoreRulesAction);
417     factory.RegisterFactoryMethod(
418         keys::kSendMessageToExtensionType,
419         DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
420         &CreateSendMessageToExtensionAction);
421   }
422 };
423 
424 base::LazyInstance<WebRequestActionFactory>::Leaky
425     g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER;
426 
427 }  // namespace
428 
429 //
430 // WebRequestAction
431 //
432 
~WebRequestAction()433 WebRequestAction::~WebRequestAction() {}
434 
Equals(const WebRequestAction * other) const435 bool WebRequestAction::Equals(const WebRequestAction* other) const {
436   return type() == other->type();
437 }
438 
HasPermission(const InfoMap * extension_info_map,const std::string & extension_id,const net::URLRequest * request,bool crosses_incognito) const439 bool WebRequestAction::HasPermission(const InfoMap* extension_info_map,
440                                      const std::string& extension_id,
441                                      const net::URLRequest* request,
442                                      bool crosses_incognito) const {
443   if (WebRequestPermissions::HideRequest(extension_info_map, request))
444     return false;
445 
446   // In unit tests we don't have an extension_info_map object here and skip host
447   // permission checks.
448   if (!extension_info_map)
449     return true;
450 
451   WebRequestPermissions::HostPermissionsCheck permission_check =
452       WebRequestPermissions::REQUIRE_ALL_URLS;
453   switch (host_permissions_strategy()) {
454     case STRATEGY_DEFAULT:  // Default value is already set.
455       break;
456     case STRATEGY_NONE:
457       permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST;
458       break;
459     case STRATEGY_HOST:
460       permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION;
461       break;
462   }
463   return WebRequestPermissions::CanExtensionAccessURL(
464       extension_info_map, extension_id, request->url(), crosses_incognito,
465       permission_check);
466 }
467 
468 // static
Create(const Extension * extension,const base::Value & json_action,std::string * error,bool * bad_message)469 scoped_refptr<const WebRequestAction> WebRequestAction::Create(
470     const Extension* extension,
471     const base::Value& json_action,
472     std::string* error,
473     bool* bad_message) {
474   *error = "";
475   *bad_message = false;
476 
477   const base::DictionaryValue* action_dict = NULL;
478   INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
479 
480   std::string instance_type;
481   INPUT_FORMAT_VALIDATE(
482       action_dict->GetString(keys::kInstanceTypeKey, &instance_type));
483 
484   WebRequestActionFactory& factory = g_web_request_action_factory.Get();
485   return factory.factory.Instantiate(
486       instance_type, action_dict, error, bad_message);
487 }
488 
Apply(const std::string & extension_id,base::Time extension_install_time,ApplyInfo * apply_info) const489 void WebRequestAction::Apply(const std::string& extension_id,
490                              base::Time extension_install_time,
491                              ApplyInfo* apply_info) const {
492   if (!HasPermission(apply_info->extension_info_map, extension_id,
493                      apply_info->request_data.request,
494                      apply_info->crosses_incognito))
495     return;
496   if (stages() & apply_info->request_data.stage) {
497     LinkedPtrEventResponseDelta delta = CreateDelta(
498         apply_info->request_data, extension_id, extension_install_time);
499     if (delta.get())
500       apply_info->deltas->push_back(delta);
501     if (type() == WebRequestAction::ACTION_IGNORE_RULES) {
502       const WebRequestIgnoreRulesAction* ignore_action =
503           static_cast<const WebRequestIgnoreRulesAction*>(this);
504       if (!ignore_action->ignore_tag().empty())
505         apply_info->ignored_tags->insert(ignore_action->ignore_tag());
506     }
507   }
508 }
509 
WebRequestAction(int stages,Type type,int minimum_priority,HostPermissionsStrategy strategy)510 WebRequestAction::WebRequestAction(int stages,
511                                    Type type,
512                                    int minimum_priority,
513                                    HostPermissionsStrategy strategy)
514     : stages_(stages),
515       type_(type),
516       minimum_priority_(minimum_priority),
517       host_permissions_strategy_(strategy) {}
518 
519 //
520 // WebRequestCancelAction
521 //
522 
WebRequestCancelAction()523 WebRequestCancelAction::WebRequestCancelAction()
524     : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
525                            ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
526                        ACTION_CANCEL_REQUEST,
527                        std::numeric_limits<int>::min(),
528                        STRATEGY_NONE) {}
529 
~WebRequestCancelAction()530 WebRequestCancelAction::~WebRequestCancelAction() {}
531 
GetName() const532 std::string WebRequestCancelAction::GetName() const {
533   return keys::kCancelRequestType;
534 }
535 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const536 LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta(
537     const WebRequestData& request_data,
538     const std::string& extension_id,
539     const base::Time& extension_install_time) const {
540   CHECK(request_data.stage & stages());
541   LinkedPtrEventResponseDelta result(
542       new helpers::EventResponseDelta(extension_id, extension_install_time));
543   result->cancel = true;
544   return result;
545 }
546 
547 //
548 // WebRequestRedirectAction
549 //
550 
WebRequestRedirectAction(const GURL & redirect_url)551 WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url)
552     : WebRequestAction(ON_BEFORE_REQUEST,
553                        ACTION_REDIRECT_REQUEST,
554                        std::numeric_limits<int>::min(),
555                        STRATEGY_DEFAULT),
556       redirect_url_(redirect_url) {}
557 
~WebRequestRedirectAction()558 WebRequestRedirectAction::~WebRequestRedirectAction() {}
559 
Equals(const WebRequestAction * other) const560 bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const {
561   return WebRequestAction::Equals(other) &&
562          redirect_url_ ==
563              static_cast<const WebRequestRedirectAction*>(other)->redirect_url_;
564 }
565 
GetName() const566 std::string WebRequestRedirectAction::GetName() const {
567   return keys::kRedirectRequestType;
568 }
569 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const570 LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta(
571     const WebRequestData& request_data,
572     const std::string& extension_id,
573     const base::Time& extension_install_time) const {
574   CHECK(request_data.stage & stages());
575   if (request_data.request->url() == redirect_url_)
576     return LinkedPtrEventResponseDelta(NULL);
577   LinkedPtrEventResponseDelta result(
578       new helpers::EventResponseDelta(extension_id, extension_install_time));
579   result->new_url = redirect_url_;
580   return result;
581 }
582 
583 //
584 // WebRequestRedirectToTransparentImageAction
585 //
586 
587 WebRequestRedirectToTransparentImageAction::
WebRequestRedirectToTransparentImageAction()588     WebRequestRedirectToTransparentImageAction()
589     : WebRequestAction(ON_BEFORE_REQUEST,
590                        ACTION_REDIRECT_TO_TRANSPARENT_IMAGE,
591                        std::numeric_limits<int>::min(),
592                        STRATEGY_NONE) {}
593 
594 WebRequestRedirectToTransparentImageAction::
~WebRequestRedirectToTransparentImageAction()595 ~WebRequestRedirectToTransparentImageAction() {}
596 
GetName() const597 std::string WebRequestRedirectToTransparentImageAction::GetName() const {
598   return keys::kRedirectToTransparentImageType;
599 }
600 
601 LinkedPtrEventResponseDelta
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const602 WebRequestRedirectToTransparentImageAction::CreateDelta(
603     const WebRequestData& request_data,
604     const std::string& extension_id,
605     const base::Time& extension_install_time) const {
606   CHECK(request_data.stage & stages());
607   LinkedPtrEventResponseDelta result(
608       new helpers::EventResponseDelta(extension_id, extension_install_time));
609   result->new_url = GURL(kTransparentImageUrl);
610   return result;
611 }
612 
613 //
614 // WebRequestRedirectToEmptyDocumentAction
615 //
616 
617 WebRequestRedirectToEmptyDocumentAction::
WebRequestRedirectToEmptyDocumentAction()618     WebRequestRedirectToEmptyDocumentAction()
619     : WebRequestAction(ON_BEFORE_REQUEST,
620                        ACTION_REDIRECT_TO_EMPTY_DOCUMENT,
621                        std::numeric_limits<int>::min(),
622                        STRATEGY_NONE) {}
623 
624 WebRequestRedirectToEmptyDocumentAction::
~WebRequestRedirectToEmptyDocumentAction()625 ~WebRequestRedirectToEmptyDocumentAction() {}
626 
GetName() const627 std::string WebRequestRedirectToEmptyDocumentAction::GetName() const {
628   return keys::kRedirectToEmptyDocumentType;
629 }
630 
631 LinkedPtrEventResponseDelta
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const632 WebRequestRedirectToEmptyDocumentAction::CreateDelta(
633     const WebRequestData& request_data,
634     const std::string& extension_id,
635     const base::Time& extension_install_time) const {
636   CHECK(request_data.stage & stages());
637   LinkedPtrEventResponseDelta result(
638       new helpers::EventResponseDelta(extension_id, extension_install_time));
639   result->new_url = GURL(kEmptyDocumentUrl);
640   return result;
641 }
642 
643 //
644 // WebRequestRedirectByRegExAction
645 //
646 
WebRequestRedirectByRegExAction(scoped_ptr<RE2> from_pattern,const std::string & to_pattern)647 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction(
648     scoped_ptr<RE2> from_pattern,
649     const std::string& to_pattern)
650     : WebRequestAction(ON_BEFORE_REQUEST,
651                        ACTION_REDIRECT_BY_REGEX_DOCUMENT,
652                        std::numeric_limits<int>::min(),
653                        STRATEGY_DEFAULT),
654       from_pattern_(from_pattern.Pass()),
655       to_pattern_(to_pattern.data(), to_pattern.size()) {}
656 
~WebRequestRedirectByRegExAction()657 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
658 
659 // About the syntax of the two languages:
660 //
661 // ICU (Perl) states:
662 // $n The text of capture group n will be substituted for $n. n must be >= 0
663 //    and not greater than the number of capture groups. A $ not followed by a
664 //    digit has no special meaning, and will appear in the substitution text
665 //    as itself, a $.
666 // \  Treat the following character as a literal, suppressing any special
667 //    meaning. Backslash escaping in substitution text is only required for
668 //    '$' and '\', but may be used on any other character without bad effects.
669 //
670 // RE2, derived from RE2::Rewrite()
671 // \  May only be followed by a digit or another \. If followed by a single
672 //    digit, both characters represent the respective capture group. If followed
673 //    by another \, it is used as an escape sequence.
674 
675 // static
PerlToRe2Style(const std::string & perl)676 std::string WebRequestRedirectByRegExAction::PerlToRe2Style(
677     const std::string& perl) {
678   std::string::const_iterator i = perl.begin();
679   std::string result;
680   while (i != perl.end()) {
681     if (*i == '$') {
682       ++i;
683       if (i == perl.end()) {
684         result += '$';
685         return result;
686       } else if (isdigit(*i)) {
687         result += '\\';
688         result += *i;
689       } else {
690         result += '$';
691         result += *i;
692       }
693     } else if (*i == '\\') {
694       ++i;
695       if (i == perl.end()) {
696         result += '\\';
697       } else if (*i == '$') {
698         result += '$';
699       } else if (*i == '\\') {
700         result += "\\\\";
701       } else {
702         result += *i;
703       }
704     } else {
705       result += *i;
706     }
707     ++i;
708   }
709   return result;
710 }
711 
Equals(const WebRequestAction * other) const712 bool WebRequestRedirectByRegExAction::Equals(
713     const WebRequestAction* other) const {
714   if (!WebRequestAction::Equals(other))
715     return false;
716   const WebRequestRedirectByRegExAction* casted_other =
717       static_cast<const WebRequestRedirectByRegExAction*>(other);
718   return from_pattern_->pattern() == casted_other->from_pattern_->pattern() &&
719          to_pattern_ == casted_other->to_pattern_;
720 }
721 
GetName() const722 std::string WebRequestRedirectByRegExAction::GetName() const {
723   return keys::kRedirectByRegExType;
724 }
725 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const726 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta(
727     const WebRequestData& request_data,
728     const std::string& extension_id,
729     const base::Time& extension_install_time) const {
730   CHECK(request_data.stage & stages());
731   CHECK(from_pattern_.get());
732 
733   const std::string& old_url = request_data.request->url().spec();
734   std::string new_url = old_url;
735   if (!RE2::Replace(&new_url, *from_pattern_, to_pattern_) ||
736       new_url == old_url) {
737     return LinkedPtrEventResponseDelta(NULL);
738   }
739 
740   LinkedPtrEventResponseDelta result(
741       new extension_web_request_api_helpers::EventResponseDelta(
742           extension_id, extension_install_time));
743   result->new_url = GURL(new_url);
744   return result;
745 }
746 
747 //
748 // WebRequestSetRequestHeaderAction
749 //
750 
WebRequestSetRequestHeaderAction(const std::string & name,const std::string & value)751 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction(
752     const std::string& name,
753     const std::string& value)
754     : WebRequestAction(ON_BEFORE_SEND_HEADERS,
755                        ACTION_SET_REQUEST_HEADER,
756                        std::numeric_limits<int>::min(),
757                        STRATEGY_DEFAULT),
758       name_(name),
759       value_(value) {}
760 
~WebRequestSetRequestHeaderAction()761 WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {}
762 
Equals(const WebRequestAction * other) const763 bool WebRequestSetRequestHeaderAction::Equals(
764     const WebRequestAction* other) const {
765   if (!WebRequestAction::Equals(other))
766     return false;
767   const WebRequestSetRequestHeaderAction* casted_other =
768       static_cast<const WebRequestSetRequestHeaderAction*>(other);
769   return name_ == casted_other->name_ && value_ == casted_other->value_;
770 }
771 
GetName() const772 std::string WebRequestSetRequestHeaderAction::GetName() const {
773   return keys::kSetRequestHeaderType;
774 }
775 
776 
777 LinkedPtrEventResponseDelta
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const778 WebRequestSetRequestHeaderAction::CreateDelta(
779     const WebRequestData& request_data,
780     const std::string& extension_id,
781     const base::Time& extension_install_time) const {
782   CHECK(request_data.stage & stages());
783   LinkedPtrEventResponseDelta result(
784       new helpers::EventResponseDelta(extension_id, extension_install_time));
785   result->modified_request_headers.SetHeader(name_, value_);
786   return result;
787 }
788 
789 //
790 // WebRequestRemoveRequestHeaderAction
791 //
792 
WebRequestRemoveRequestHeaderAction(const std::string & name)793 WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction(
794     const std::string& name)
795     : WebRequestAction(ON_BEFORE_SEND_HEADERS,
796                        ACTION_REMOVE_REQUEST_HEADER,
797                        std::numeric_limits<int>::min(),
798                        STRATEGY_DEFAULT),
799       name_(name) {}
800 
~WebRequestRemoveRequestHeaderAction()801 WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {}
802 
Equals(const WebRequestAction * other) const803 bool WebRequestRemoveRequestHeaderAction::Equals(
804     const WebRequestAction* other) const {
805   if (!WebRequestAction::Equals(other))
806     return false;
807   const WebRequestRemoveRequestHeaderAction* casted_other =
808       static_cast<const WebRequestRemoveRequestHeaderAction*>(other);
809   return name_ == casted_other->name_;
810 }
811 
GetName() const812 std::string WebRequestRemoveRequestHeaderAction::GetName() const {
813   return keys::kRemoveRequestHeaderType;
814 }
815 
816 LinkedPtrEventResponseDelta
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const817 WebRequestRemoveRequestHeaderAction::CreateDelta(
818     const WebRequestData& request_data,
819     const std::string& extension_id,
820     const base::Time& extension_install_time) const {
821   CHECK(request_data.stage & stages());
822   LinkedPtrEventResponseDelta result(
823       new helpers::EventResponseDelta(extension_id, extension_install_time));
824   result->deleted_request_headers.push_back(name_);
825   return result;
826 }
827 
828 //
829 // WebRequestAddResponseHeaderAction
830 //
831 
WebRequestAddResponseHeaderAction(const std::string & name,const std::string & value)832 WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction(
833     const std::string& name,
834     const std::string& value)
835     : WebRequestAction(ON_HEADERS_RECEIVED,
836                        ACTION_ADD_RESPONSE_HEADER,
837                        std::numeric_limits<int>::min(),
838                        STRATEGY_DEFAULT),
839       name_(name),
840       value_(value) {}
841 
~WebRequestAddResponseHeaderAction()842 WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {}
843 
Equals(const WebRequestAction * other) const844 bool WebRequestAddResponseHeaderAction::Equals(
845     const WebRequestAction* other) const {
846   if (!WebRequestAction::Equals(other))
847     return false;
848   const WebRequestAddResponseHeaderAction* casted_other =
849       static_cast<const WebRequestAddResponseHeaderAction*>(other);
850   return name_ == casted_other->name_ && value_ == casted_other->value_;
851 }
852 
GetName() const853 std::string WebRequestAddResponseHeaderAction::GetName() const {
854   return keys::kAddResponseHeaderType;
855 }
856 
857 LinkedPtrEventResponseDelta
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const858 WebRequestAddResponseHeaderAction::CreateDelta(
859     const WebRequestData& request_data,
860     const std::string& extension_id,
861     const base::Time& extension_install_time) const {
862   CHECK(request_data.stage & stages());
863   const net::HttpResponseHeaders* headers =
864       request_data.original_response_headers;
865   if (!headers)
866     return LinkedPtrEventResponseDelta(NULL);
867 
868   // Don't generate the header if it exists already.
869   if (headers->HasHeaderValue(name_, value_))
870     return LinkedPtrEventResponseDelta(NULL);
871 
872   LinkedPtrEventResponseDelta result(
873       new helpers::EventResponseDelta(extension_id, extension_install_time));
874   result->added_response_headers.push_back(make_pair(name_, value_));
875   return result;
876 }
877 
878 //
879 // WebRequestRemoveResponseHeaderAction
880 //
881 
WebRequestRemoveResponseHeaderAction(const std::string & name,const std::string & value,bool has_value)882 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction(
883     const std::string& name,
884     const std::string& value,
885     bool has_value)
886     : WebRequestAction(ON_HEADERS_RECEIVED,
887                        ACTION_REMOVE_RESPONSE_HEADER,
888                        std::numeric_limits<int>::min(),
889                        STRATEGY_DEFAULT),
890       name_(name),
891       value_(value),
892       has_value_(has_value) {}
893 
~WebRequestRemoveResponseHeaderAction()894 WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {}
895 
Equals(const WebRequestAction * other) const896 bool WebRequestRemoveResponseHeaderAction::Equals(
897     const WebRequestAction* other) const {
898   if (!WebRequestAction::Equals(other))
899     return false;
900   const WebRequestRemoveResponseHeaderAction* casted_other =
901       static_cast<const WebRequestRemoveResponseHeaderAction*>(other);
902   return name_ == casted_other->name_ && value_ == casted_other->value_ &&
903          has_value_ == casted_other->has_value_;
904 }
905 
GetName() const906 std::string WebRequestRemoveResponseHeaderAction::GetName() const {
907   return keys::kRemoveResponseHeaderType;
908 }
909 
910 LinkedPtrEventResponseDelta
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const911 WebRequestRemoveResponseHeaderAction::CreateDelta(
912     const WebRequestData& request_data,
913     const std::string& extension_id,
914     const base::Time& extension_install_time) const {
915   CHECK(request_data.stage & stages());
916   const net::HttpResponseHeaders* headers =
917       request_data.original_response_headers;
918   if (!headers)
919     return LinkedPtrEventResponseDelta(NULL);
920 
921   LinkedPtrEventResponseDelta result(
922       new helpers::EventResponseDelta(extension_id, extension_install_time));
923   void* iter = NULL;
924   std::string current_value;
925   while (headers->EnumerateHeader(&iter, name_, &current_value)) {
926     if (has_value_ &&
927            (current_value.size() != value_.size() ||
928             !std::equal(current_value.begin(), current_value.end(),
929                         value_.begin(),
930                         base::CaseInsensitiveCompare<char>()))) {
931       continue;
932     }
933     result->deleted_response_headers.push_back(make_pair(name_, current_value));
934   }
935   return result;
936 }
937 
938 //
939 // WebRequestIgnoreRulesAction
940 //
941 
WebRequestIgnoreRulesAction(int minimum_priority,const std::string & ignore_tag)942 WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction(
943     int minimum_priority,
944     const std::string& ignore_tag)
945     : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
946                            ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
947                        ACTION_IGNORE_RULES,
948                        minimum_priority,
949                        STRATEGY_NONE),
950       ignore_tag_(ignore_tag) {}
951 
~WebRequestIgnoreRulesAction()952 WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {}
953 
Equals(const WebRequestAction * other) const954 bool WebRequestIgnoreRulesAction::Equals(const WebRequestAction* other) const {
955   if (!WebRequestAction::Equals(other))
956     return false;
957   const WebRequestIgnoreRulesAction* casted_other =
958       static_cast<const WebRequestIgnoreRulesAction*>(other);
959   return minimum_priority() == casted_other->minimum_priority() &&
960          ignore_tag_ == casted_other->ignore_tag_;
961 }
962 
GetName() const963 std::string WebRequestIgnoreRulesAction::GetName() const {
964   return keys::kIgnoreRulesType;
965 }
966 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const967 LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta(
968     const WebRequestData& request_data,
969     const std::string& extension_id,
970     const base::Time& extension_install_time) const {
971   CHECK(request_data.stage & stages());
972   return LinkedPtrEventResponseDelta(NULL);
973 }
974 
975 //
976 // WebRequestRequestCookieAction
977 //
978 
WebRequestRequestCookieAction(linked_ptr<RequestCookieModification> request_cookie_modification)979 WebRequestRequestCookieAction::WebRequestRequestCookieAction(
980     linked_ptr<RequestCookieModification> request_cookie_modification)
981     : WebRequestAction(ON_BEFORE_SEND_HEADERS,
982                        ACTION_MODIFY_REQUEST_COOKIE,
983                        std::numeric_limits<int>::min(),
984                        STRATEGY_DEFAULT),
985       request_cookie_modification_(request_cookie_modification) {
986   CHECK(request_cookie_modification_.get());
987 }
988 
~WebRequestRequestCookieAction()989 WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
990 
Equals(const WebRequestAction * other) const991 bool WebRequestRequestCookieAction::Equals(
992     const WebRequestAction* other) const {
993   if (!WebRequestAction::Equals(other))
994     return false;
995   const WebRequestRequestCookieAction* casted_other =
996       static_cast<const WebRequestRequestCookieAction*>(other);
997   return helpers::NullableEquals(
998       request_cookie_modification_.get(),
999       casted_other->request_cookie_modification_.get());
1000 }
1001 
GetName() const1002 std::string WebRequestRequestCookieAction::GetName() const {
1003   switch (request_cookie_modification_->type) {
1004     case helpers::ADD:
1005       return keys::kAddRequestCookieType;
1006     case helpers::EDIT:
1007       return keys::kEditRequestCookieType;
1008     case helpers::REMOVE:
1009       return keys::kRemoveRequestCookieType;
1010   }
1011   NOTREACHED();
1012   return "";
1013 }
1014 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const1015 LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta(
1016     const WebRequestData& request_data,
1017     const std::string& extension_id,
1018     const base::Time& extension_install_time) const {
1019   CHECK(request_data.stage & stages());
1020   LinkedPtrEventResponseDelta result(
1021       new extension_web_request_api_helpers::EventResponseDelta(
1022           extension_id, extension_install_time));
1023   result->request_cookie_modifications.push_back(
1024       request_cookie_modification_);
1025   return result;
1026 }
1027 
1028 //
1029 // WebRequestResponseCookieAction
1030 //
1031 
WebRequestResponseCookieAction(linked_ptr<ResponseCookieModification> response_cookie_modification)1032 WebRequestResponseCookieAction::WebRequestResponseCookieAction(
1033     linked_ptr<ResponseCookieModification> response_cookie_modification)
1034     : WebRequestAction(ON_HEADERS_RECEIVED,
1035                        ACTION_MODIFY_RESPONSE_COOKIE,
1036                        std::numeric_limits<int>::min(),
1037                        STRATEGY_DEFAULT),
1038       response_cookie_modification_(response_cookie_modification) {
1039   CHECK(response_cookie_modification_.get());
1040 }
1041 
~WebRequestResponseCookieAction()1042 WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
1043 
Equals(const WebRequestAction * other) const1044 bool WebRequestResponseCookieAction::Equals(
1045     const WebRequestAction* other) const {
1046   if (!WebRequestAction::Equals(other))
1047     return false;
1048   const WebRequestResponseCookieAction* casted_other =
1049       static_cast<const WebRequestResponseCookieAction*>(other);
1050   return helpers::NullableEquals(
1051       response_cookie_modification_.get(),
1052       casted_other->response_cookie_modification_.get());
1053 }
1054 
GetName() const1055 std::string WebRequestResponseCookieAction::GetName() const {
1056   switch (response_cookie_modification_->type) {
1057     case helpers::ADD:
1058       return keys::kAddResponseCookieType;
1059     case helpers::EDIT:
1060       return keys::kEditResponseCookieType;
1061     case helpers::REMOVE:
1062       return keys::kRemoveResponseCookieType;
1063   }
1064   NOTREACHED();
1065   return "";
1066 }
1067 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const1068 LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta(
1069     const WebRequestData& request_data,
1070     const std::string& extension_id,
1071     const base::Time& extension_install_time) const {
1072   CHECK(request_data.stage & stages());
1073   LinkedPtrEventResponseDelta result(
1074       new extension_web_request_api_helpers::EventResponseDelta(
1075           extension_id, extension_install_time));
1076   result->response_cookie_modifications.push_back(
1077       response_cookie_modification_);
1078   return result;
1079 }
1080 
1081 //
1082 // WebRequestSendMessageToExtensionAction
1083 //
1084 
WebRequestSendMessageToExtensionAction(const std::string & message)1085 WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction(
1086     const std::string& message)
1087     : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
1088                            ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
1089                        ACTION_SEND_MESSAGE_TO_EXTENSION,
1090                        std::numeric_limits<int>::min(),
1091                        STRATEGY_HOST),
1092       message_(message) {}
1093 
1094 WebRequestSendMessageToExtensionAction::
~WebRequestSendMessageToExtensionAction()1095 ~WebRequestSendMessageToExtensionAction() {}
1096 
Equals(const WebRequestAction * other) const1097 bool WebRequestSendMessageToExtensionAction::Equals(
1098     const WebRequestAction* other) const {
1099   if (!WebRequestAction::Equals(other))
1100     return false;
1101   const WebRequestSendMessageToExtensionAction* casted_other =
1102       static_cast<const WebRequestSendMessageToExtensionAction*>(other);
1103   return message_ == casted_other->message_;
1104 }
1105 
GetName() const1106 std::string WebRequestSendMessageToExtensionAction::GetName() const {
1107   return keys::kSendMessageToExtensionType;
1108 }
1109 
CreateDelta(const WebRequestData & request_data,const std::string & extension_id,const base::Time & extension_install_time) const1110 LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta(
1111     const WebRequestData& request_data,
1112     const std::string& extension_id,
1113     const base::Time& extension_install_time) const {
1114   CHECK(request_data.stage & stages());
1115   LinkedPtrEventResponseDelta result(
1116       new extension_web_request_api_helpers::EventResponseDelta(
1117           extension_id, extension_install_time));
1118   result->messages_to_extension.insert(message_);
1119   return result;
1120 }
1121 
1122 }  // namespace extensions
1123