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