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