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_, ¤t_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