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.
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/declarative/deduping_factory.h"
15 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
16 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"
17 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
18 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h"
19 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
20 #include "chrome/browser/extensions/api/web_request/web_request_permissions.h"
21 #include "chrome/browser/guest_view/web_view/web_view_renderer_state.h"
22 #include "content/public/browser/resource_request_info.h"
23 #include "content/public/common/url_constants.h"
24 #include "extensions/browser/info_map.h"
25 #include "extensions/common/error_utils.h"
26 #include "extensions/common/extension.h"
27 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
28 #include "net/url_request/url_request.h"
29 #include "third_party/re2/re2/re2.h"
31 using content::ResourceRequestInfo;
33 namespace extensions {
35 namespace helpers = extension_web_request_api_helpers;
36 namespace keys = declarative_webrequest_constants;
40 const char kIgnoreRulesRequiresParameterError[] =
41 "IgnoreRules requires at least one parameter.";
43 const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh"
44 "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==";
45 const char kEmptyDocumentUrl[] = "data:text/html,";
47 #define INPUT_FORMAT_VALIDATE(test) do { \
49 *bad_message = true; \
50 return scoped_refptr<const WebRequestAction>(NULL); \
54 scoped_ptr<helpers::RequestCookie> ParseRequestCookie(
55 const base::DictionaryValue* dict) {
56 scoped_ptr<helpers::RequestCookie> result(new helpers::RequestCookie);
58 if (dict->GetString(keys::kNameKey, &tmp))
59 result->name.reset(new std::string(tmp));
60 if (dict->GetString(keys::kValueKey, &tmp))
61 result->value.reset(new std::string(tmp));
65 void ParseResponseCookieImpl(const base::DictionaryValue* dict,
66 helpers::ResponseCookie* cookie) {
67 std::string string_tmp;
69 bool bool_tmp = false;
70 if (dict->GetString(keys::kNameKey, &string_tmp))
71 cookie->name.reset(new std::string(string_tmp));
72 if (dict->GetString(keys::kValueKey, &string_tmp))
73 cookie->value.reset(new std::string(string_tmp));
74 if (dict->GetString(keys::kExpiresKey, &string_tmp))
75 cookie->expires.reset(new std::string(string_tmp));
76 if (dict->GetInteger(keys::kMaxAgeKey, &int_tmp))
77 cookie->max_age.reset(new int(int_tmp));
78 if (dict->GetString(keys::kDomainKey, &string_tmp))
79 cookie->domain.reset(new std::string(string_tmp));
80 if (dict->GetString(keys::kPathKey, &string_tmp))
81 cookie->path.reset(new std::string(string_tmp));
82 if (dict->GetBoolean(keys::kSecureKey, &bool_tmp))
83 cookie->secure.reset(new bool(bool_tmp));
84 if (dict->GetBoolean(keys::kHttpOnlyKey, &bool_tmp))
85 cookie->http_only.reset(new bool(bool_tmp));
88 scoped_ptr<helpers::ResponseCookie> ParseResponseCookie(
89 const base::DictionaryValue* dict) {
90 scoped_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie);
91 ParseResponseCookieImpl(dict, result.get());
95 scoped_ptr<helpers::FilterResponseCookie> ParseFilterResponseCookie(
96 const base::DictionaryValue* dict) {
97 scoped_ptr<helpers::FilterResponseCookie> result(
98 new helpers::FilterResponseCookie);
99 ParseResponseCookieImpl(dict, result.get());
102 bool bool_tmp = false;
103 if (dict->GetInteger(keys::kAgeUpperBoundKey, &int_tmp))
104 result->age_upper_bound.reset(new int(int_tmp));
105 if (dict->GetInteger(keys::kAgeLowerBoundKey, &int_tmp))
106 result->age_lower_bound.reset(new int(int_tmp));
107 if (dict->GetBoolean(keys::kSessionCookieKey, &bool_tmp))
108 result->session_cookie.reset(new bool(bool_tmp));
109 return result.Pass();
112 // Helper function for WebRequestActions that can be instantiated by just
113 // calling the constructor.
115 scoped_refptr<const WebRequestAction> CallConstructorFactoryMethod(
116 const std::string& instance_type,
117 const base::Value* value,
120 return scoped_refptr<const WebRequestAction>(new T);
123 scoped_refptr<const WebRequestAction> CreateRedirectRequestAction(
124 const std::string& instance_type,
125 const base::Value* value,
128 const base::DictionaryValue* dict = NULL;
129 CHECK(value->GetAsDictionary(&dict));
130 std::string redirect_url_string;
131 INPUT_FORMAT_VALIDATE(
132 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string));
133 GURL redirect_url(redirect_url_string);
134 return scoped_refptr<const WebRequestAction>(
135 new WebRequestRedirectAction(redirect_url));
138 scoped_refptr<const WebRequestAction> CreateRedirectRequestByRegExAction(
139 const std::string& instance_type,
140 const base::Value* value,
143 const base::DictionaryValue* dict = NULL;
144 CHECK(value->GetAsDictionary(&dict));
147 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from));
148 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to));
150 to = WebRequestRedirectByRegExAction::PerlToRe2Style(to);
152 RE2::Options options;
153 options.set_case_sensitive(false);
154 scoped_ptr<RE2> from_pattern(new RE2(from, options));
156 if (!from_pattern->ok()) {
157 *error = "Invalid pattern '" + from + "' -> '" + to + "'";
158 return scoped_refptr<const WebRequestAction>(NULL);
160 return scoped_refptr<const WebRequestAction>(
161 new WebRequestRedirectByRegExAction(from_pattern.Pass(), to));
164 scoped_refptr<const WebRequestAction> CreateSetRequestHeaderAction(
165 const std::string& instance_type,
166 const base::Value* json_value,
169 const base::DictionaryValue* dict = NULL;
170 CHECK(json_value->GetAsDictionary(&dict));
173 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
174 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
175 if (!helpers::IsValidHeaderName(name)) {
176 *error = extension_web_request_api_constants::kInvalidHeaderName;
177 return scoped_refptr<const WebRequestAction>(NULL);
179 if (!helpers::IsValidHeaderValue(value)) {
180 *error = ErrorUtils::FormatErrorMessage(
181 extension_web_request_api_constants::kInvalidHeaderValue, name);
182 return scoped_refptr<const WebRequestAction>(NULL);
184 return scoped_refptr<const WebRequestAction>(
185 new WebRequestSetRequestHeaderAction(name, value));
188 scoped_refptr<const WebRequestAction> CreateRemoveRequestHeaderAction(
189 const std::string& instance_type,
190 const base::Value* value,
193 const base::DictionaryValue* dict = NULL;
194 CHECK(value->GetAsDictionary(&dict));
196 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
197 if (!helpers::IsValidHeaderName(name)) {
198 *error = extension_web_request_api_constants::kInvalidHeaderName;
199 return scoped_refptr<const WebRequestAction>(NULL);
201 return scoped_refptr<const WebRequestAction>(
202 new WebRequestRemoveRequestHeaderAction(name));
205 scoped_refptr<const WebRequestAction> CreateAddResponseHeaderAction(
206 const std::string& instance_type,
207 const base::Value* json_value,
210 const base::DictionaryValue* dict = NULL;
211 CHECK(json_value->GetAsDictionary(&dict));
214 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
215 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
216 if (!helpers::IsValidHeaderName(name)) {
217 *error = extension_web_request_api_constants::kInvalidHeaderName;
218 return scoped_refptr<const WebRequestAction>(NULL);
220 if (!helpers::IsValidHeaderValue(value)) {
221 *error = ErrorUtils::FormatErrorMessage(
222 extension_web_request_api_constants::kInvalidHeaderValue, name);
223 return scoped_refptr<const WebRequestAction>(NULL);
225 return scoped_refptr<const WebRequestAction>(
226 new WebRequestAddResponseHeaderAction(name, value));
229 scoped_refptr<const WebRequestAction> CreateRemoveResponseHeaderAction(
230 const std::string& instance_type,
231 const base::Value* json_value,
234 const base::DictionaryValue* dict = NULL;
235 CHECK(json_value->GetAsDictionary(&dict));
238 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
239 bool has_value = dict->GetString(keys::kValueKey, &value);
240 if (!helpers::IsValidHeaderName(name)) {
241 *error = extension_web_request_api_constants::kInvalidHeaderName;
242 return scoped_refptr<const WebRequestAction>(NULL);
244 if (has_value && !helpers::IsValidHeaderValue(value)) {
245 *error = ErrorUtils::FormatErrorMessage(
246 extension_web_request_api_constants::kInvalidHeaderValue, name);
247 return scoped_refptr<const WebRequestAction>(NULL);
249 return scoped_refptr<const WebRequestAction>(
250 new WebRequestRemoveResponseHeaderAction(name, value, has_value));
253 scoped_refptr<const WebRequestAction> CreateIgnoreRulesAction(
254 const std::string& instance_type,
255 const base::Value* value,
258 const base::DictionaryValue* dict = NULL;
259 CHECK(value->GetAsDictionary(&dict));
260 bool has_parameter = false;
261 int minimum_priority = std::numeric_limits<int>::min();
262 std::string ignore_tag;
263 if (dict->HasKey(keys::kLowerPriorityThanKey)) {
264 INPUT_FORMAT_VALIDATE(
265 dict->GetInteger(keys::kLowerPriorityThanKey, &minimum_priority));
266 has_parameter = true;
268 if (dict->HasKey(keys::kHasTagKey)) {
269 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kHasTagKey, &ignore_tag));
270 has_parameter = true;
272 if (!has_parameter) {
273 *error = kIgnoreRulesRequiresParameterError;
274 return scoped_refptr<const WebRequestAction>(NULL);
276 return scoped_refptr<const WebRequestAction>(
277 new WebRequestIgnoreRulesAction(minimum_priority, ignore_tag));
280 scoped_refptr<const WebRequestAction> CreateRequestCookieAction(
281 const std::string& instance_type,
282 const base::Value* value,
285 using extension_web_request_api_helpers::RequestCookieModification;
287 const base::DictionaryValue* dict = NULL;
288 CHECK(value->GetAsDictionary(&dict));
290 linked_ptr<RequestCookieModification> modification(
291 new RequestCookieModification);
293 // Get modification type.
294 if (instance_type == keys::kAddRequestCookieType)
295 modification->type = helpers::ADD;
296 else if (instance_type == keys::kEditRequestCookieType)
297 modification->type = helpers::EDIT;
298 else if (instance_type == keys::kRemoveRequestCookieType)
299 modification->type = helpers::REMOVE;
301 INPUT_FORMAT_VALIDATE(false);
304 if (modification->type == helpers::EDIT ||
305 modification->type == helpers::REMOVE) {
306 const base::DictionaryValue* filter = NULL;
307 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
308 modification->filter = ParseRequestCookie(filter);
312 if (modification->type == helpers::ADD) {
313 const base::DictionaryValue* value = NULL;
314 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
315 modification->modification = ParseRequestCookie(value);
316 } else if (modification->type == helpers::EDIT) {
317 const base::DictionaryValue* value = NULL;
318 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
319 modification->modification = ParseRequestCookie(value);
322 return scoped_refptr<const WebRequestAction>(
323 new WebRequestRequestCookieAction(modification));
326 scoped_refptr<const WebRequestAction> CreateResponseCookieAction(
327 const std::string& instance_type,
328 const base::Value* value,
331 using extension_web_request_api_helpers::ResponseCookieModification;
333 const base::DictionaryValue* dict = NULL;
334 CHECK(value->GetAsDictionary(&dict));
336 linked_ptr<ResponseCookieModification> modification(
337 new ResponseCookieModification);
339 // Get modification type.
340 if (instance_type == keys::kAddResponseCookieType)
341 modification->type = helpers::ADD;
342 else if (instance_type == keys::kEditResponseCookieType)
343 modification->type = helpers::EDIT;
344 else if (instance_type == keys::kRemoveResponseCookieType)
345 modification->type = helpers::REMOVE;
347 INPUT_FORMAT_VALIDATE(false);
350 if (modification->type == helpers::EDIT ||
351 modification->type == helpers::REMOVE) {
352 const base::DictionaryValue* filter = NULL;
353 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
354 modification->filter = ParseFilterResponseCookie(filter);
358 if (modification->type == helpers::ADD) {
359 const base::DictionaryValue* value = NULL;
360 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
361 modification->modification = ParseResponseCookie(value);
362 } else if (modification->type == helpers::EDIT) {
363 const base::DictionaryValue* value = NULL;
364 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
365 modification->modification = ParseResponseCookie(value);
368 return scoped_refptr<const WebRequestAction>(
369 new WebRequestResponseCookieAction(modification));
372 scoped_refptr<const WebRequestAction> CreateSendMessageToExtensionAction(
373 const std::string& name,
374 const base::Value* value,
377 const base::DictionaryValue* dict = NULL;
378 CHECK(value->GetAsDictionary(&dict));
380 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kMessageKey, &message));
381 return scoped_refptr<const WebRequestAction>(
382 new WebRequestSendMessageToExtensionAction(message));
385 struct WebRequestActionFactory {
386 DedupingFactory<WebRequestAction> factory;
388 WebRequestActionFactory() : factory(5) {
389 factory.RegisterFactoryMethod(
390 keys::kAddRequestCookieType,
391 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
392 &CreateRequestCookieAction);
393 factory.RegisterFactoryMethod(
394 keys::kAddResponseCookieType,
395 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
396 &CreateResponseCookieAction);
397 factory.RegisterFactoryMethod(
398 keys::kAddResponseHeaderType,
399 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
400 &CreateAddResponseHeaderAction);
401 factory.RegisterFactoryMethod(
402 keys::kCancelRequestType,
403 DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
404 &CallConstructorFactoryMethod<WebRequestCancelAction>);
405 factory.RegisterFactoryMethod(
406 keys::kEditRequestCookieType,
407 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
408 &CreateRequestCookieAction);
409 factory.RegisterFactoryMethod(
410 keys::kEditResponseCookieType,
411 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
412 &CreateResponseCookieAction);
413 factory.RegisterFactoryMethod(
414 keys::kRedirectByRegExType,
415 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
416 &CreateRedirectRequestByRegExAction);
417 factory.RegisterFactoryMethod(
418 keys::kRedirectRequestType,
419 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
420 &CreateRedirectRequestAction);
421 factory.RegisterFactoryMethod(
422 keys::kRedirectToTransparentImageType,
423 DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
424 &CallConstructorFactoryMethod<
425 WebRequestRedirectToTransparentImageAction>);
426 factory.RegisterFactoryMethod(
427 keys::kRedirectToEmptyDocumentType,
428 DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
429 &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>);
430 factory.RegisterFactoryMethod(
431 keys::kRemoveRequestCookieType,
432 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
433 &CreateRequestCookieAction);
434 factory.RegisterFactoryMethod(
435 keys::kRemoveResponseCookieType,
436 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
437 &CreateResponseCookieAction);
438 factory.RegisterFactoryMethod(
439 keys::kSetRequestHeaderType,
440 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
441 &CreateSetRequestHeaderAction);
442 factory.RegisterFactoryMethod(
443 keys::kRemoveRequestHeaderType,
444 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
445 &CreateRemoveRequestHeaderAction);
446 factory.RegisterFactoryMethod(
447 keys::kRemoveResponseHeaderType,
448 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
449 &CreateRemoveResponseHeaderAction);
450 factory.RegisterFactoryMethod(
451 keys::kIgnoreRulesType,
452 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
453 &CreateIgnoreRulesAction);
454 factory.RegisterFactoryMethod(
455 keys::kSendMessageToExtensionType,
456 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
457 &CreateSendMessageToExtensionAction);
461 base::LazyInstance<WebRequestActionFactory>::Leaky
462 g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER;
470 WebRequestAction::~WebRequestAction() {}
472 bool WebRequestAction::Equals(const WebRequestAction* other) const {
473 return type() == other->type();
476 bool WebRequestAction::HasPermission(const InfoMap* extension_info_map,
477 const std::string& extension_id,
478 const net::URLRequest* request,
479 bool crosses_incognito) const {
480 if (WebRequestPermissions::HideRequest(extension_info_map, request))
483 // In unit tests we don't have an extension_info_map object here and skip host
484 // permission checks.
485 if (!extension_info_map)
488 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
489 int process_id = info ? info->GetChildID() : 0;
491 // The embedder can always access all hosts from within a <webview>.
492 // The same is not true of extensions.
493 if (WebViewRendererState::GetInstance()->IsGuest(process_id))
496 WebRequestPermissions::HostPermissionsCheck permission_check =
497 WebRequestPermissions::REQUIRE_ALL_URLS;
498 switch (host_permissions_strategy()) {
499 case STRATEGY_DEFAULT: // Default value is already set.
502 permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST;
505 permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION;
508 return WebRequestPermissions::CanExtensionAccessURL(
509 extension_info_map, extension_id, request->url(), crosses_incognito,
514 scoped_refptr<const WebRequestAction> WebRequestAction::Create(
515 const Extension* extension,
516 const base::Value& json_action,
520 *bad_message = false;
522 const base::DictionaryValue* action_dict = NULL;
523 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
525 std::string instance_type;
526 INPUT_FORMAT_VALIDATE(
527 action_dict->GetString(keys::kInstanceTypeKey, &instance_type));
529 WebRequestActionFactory& factory = g_web_request_action_factory.Get();
530 return factory.factory.Instantiate(
531 instance_type, action_dict, error, bad_message);
534 void WebRequestAction::Apply(const std::string& extension_id,
535 base::Time extension_install_time,
536 ApplyInfo* apply_info) const {
537 if (!HasPermission(apply_info->extension_info_map, extension_id,
538 apply_info->request_data.request,
539 apply_info->crosses_incognito))
541 if (stages() & apply_info->request_data.stage) {
542 LinkedPtrEventResponseDelta delta = CreateDelta(
543 apply_info->request_data, extension_id, extension_install_time);
545 apply_info->deltas->push_back(delta);
546 if (type() == WebRequestAction::ACTION_IGNORE_RULES) {
547 const WebRequestIgnoreRulesAction* ignore_action =
548 static_cast<const WebRequestIgnoreRulesAction*>(this);
549 if (!ignore_action->ignore_tag().empty())
550 apply_info->ignored_tags->insert(ignore_action->ignore_tag());
555 WebRequestAction::WebRequestAction(int stages,
557 int minimum_priority,
558 HostPermissionsStrategy strategy)
561 minimum_priority_(minimum_priority),
562 host_permissions_strategy_(strategy) {}
565 // WebRequestCancelAction
568 WebRequestCancelAction::WebRequestCancelAction()
569 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
570 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
571 ACTION_CANCEL_REQUEST,
572 std::numeric_limits<int>::min(),
575 WebRequestCancelAction::~WebRequestCancelAction() {}
577 std::string WebRequestCancelAction::GetName() const {
578 return keys::kCancelRequestType;
581 LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta(
582 const WebRequestData& request_data,
583 const std::string& extension_id,
584 const base::Time& extension_install_time) const {
585 CHECK(request_data.stage & stages());
586 LinkedPtrEventResponseDelta result(
587 new helpers::EventResponseDelta(extension_id, extension_install_time));
588 result->cancel = true;
593 // WebRequestRedirectAction
596 WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url)
597 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
598 ACTION_REDIRECT_REQUEST,
599 std::numeric_limits<int>::min(),
601 redirect_url_(redirect_url) {}
603 WebRequestRedirectAction::~WebRequestRedirectAction() {}
605 bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const {
606 return WebRequestAction::Equals(other) &&
608 static_cast<const WebRequestRedirectAction*>(other)->redirect_url_;
611 std::string WebRequestRedirectAction::GetName() const {
612 return keys::kRedirectRequestType;
615 LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta(
616 const WebRequestData& request_data,
617 const std::string& extension_id,
618 const base::Time& extension_install_time) const {
619 CHECK(request_data.stage & stages());
620 if (request_data.request->url() == redirect_url_)
621 return LinkedPtrEventResponseDelta(NULL);
622 LinkedPtrEventResponseDelta result(
623 new helpers::EventResponseDelta(extension_id, extension_install_time));
624 result->new_url = redirect_url_;
629 // WebRequestRedirectToTransparentImageAction
632 WebRequestRedirectToTransparentImageAction::
633 WebRequestRedirectToTransparentImageAction()
634 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
635 ACTION_REDIRECT_TO_TRANSPARENT_IMAGE,
636 std::numeric_limits<int>::min(),
639 WebRequestRedirectToTransparentImageAction::
640 ~WebRequestRedirectToTransparentImageAction() {}
642 std::string WebRequestRedirectToTransparentImageAction::GetName() const {
643 return keys::kRedirectToTransparentImageType;
646 LinkedPtrEventResponseDelta
647 WebRequestRedirectToTransparentImageAction::CreateDelta(
648 const WebRequestData& request_data,
649 const std::string& extension_id,
650 const base::Time& extension_install_time) const {
651 CHECK(request_data.stage & stages());
652 LinkedPtrEventResponseDelta result(
653 new helpers::EventResponseDelta(extension_id, extension_install_time));
654 result->new_url = GURL(kTransparentImageUrl);
659 // WebRequestRedirectToEmptyDocumentAction
662 WebRequestRedirectToEmptyDocumentAction::
663 WebRequestRedirectToEmptyDocumentAction()
664 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
665 ACTION_REDIRECT_TO_EMPTY_DOCUMENT,
666 std::numeric_limits<int>::min(),
669 WebRequestRedirectToEmptyDocumentAction::
670 ~WebRequestRedirectToEmptyDocumentAction() {}
672 std::string WebRequestRedirectToEmptyDocumentAction::GetName() const {
673 return keys::kRedirectToEmptyDocumentType;
676 LinkedPtrEventResponseDelta
677 WebRequestRedirectToEmptyDocumentAction::CreateDelta(
678 const WebRequestData& request_data,
679 const std::string& extension_id,
680 const base::Time& extension_install_time) const {
681 CHECK(request_data.stage & stages());
682 LinkedPtrEventResponseDelta result(
683 new helpers::EventResponseDelta(extension_id, extension_install_time));
684 result->new_url = GURL(kEmptyDocumentUrl);
689 // WebRequestRedirectByRegExAction
692 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction(
693 scoped_ptr<RE2> from_pattern,
694 const std::string& to_pattern)
695 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
696 ACTION_REDIRECT_BY_REGEX_DOCUMENT,
697 std::numeric_limits<int>::min(),
699 from_pattern_(from_pattern.Pass()),
700 to_pattern_(to_pattern.data(), to_pattern.size()) {}
702 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
704 // About the syntax of the two languages:
706 // ICU (Perl) states:
707 // $n The text of capture group n will be substituted for $n. n must be >= 0
708 // and not greater than the number of capture groups. A $ not followed by a
709 // digit has no special meaning, and will appear in the substitution text
711 // \ Treat the following character as a literal, suppressing any special
712 // meaning. Backslash escaping in substitution text is only required for
713 // '$' and '\', but may be used on any other character without bad effects.
715 // RE2, derived from RE2::Rewrite()
716 // \ May only be followed by a digit or another \. If followed by a single
717 // digit, both characters represent the respective capture group. If followed
718 // by another \, it is used as an escape sequence.
721 std::string WebRequestRedirectByRegExAction::PerlToRe2Style(
722 const std::string& perl) {
723 std::string::const_iterator i = perl.begin();
725 while (i != perl.end()) {
728 if (i == perl.end()) {
731 } else if (isdigit(*i)) {
738 } else if (*i == '\\') {
740 if (i == perl.end()) {
742 } else if (*i == '$') {
744 } else if (*i == '\\') {
757 bool WebRequestRedirectByRegExAction::Equals(
758 const WebRequestAction* other) const {
759 if (!WebRequestAction::Equals(other))
761 const WebRequestRedirectByRegExAction* casted_other =
762 static_cast<const WebRequestRedirectByRegExAction*>(other);
763 return from_pattern_->pattern() == casted_other->from_pattern_->pattern() &&
764 to_pattern_ == casted_other->to_pattern_;
767 std::string WebRequestRedirectByRegExAction::GetName() const {
768 return keys::kRedirectByRegExType;
771 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta(
772 const WebRequestData& request_data,
773 const std::string& extension_id,
774 const base::Time& extension_install_time) const {
775 CHECK(request_data.stage & stages());
776 CHECK(from_pattern_.get());
778 const std::string& old_url = request_data.request->url().spec();
779 std::string new_url = old_url;
780 if (!RE2::Replace(&new_url, *from_pattern_, to_pattern_) ||
781 new_url == old_url) {
782 return LinkedPtrEventResponseDelta(NULL);
785 LinkedPtrEventResponseDelta result(
786 new extension_web_request_api_helpers::EventResponseDelta(
787 extension_id, extension_install_time));
788 result->new_url = GURL(new_url);
793 // WebRequestSetRequestHeaderAction
796 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction(
797 const std::string& name,
798 const std::string& value)
799 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
800 ACTION_SET_REQUEST_HEADER,
801 std::numeric_limits<int>::min(),
806 WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {}
808 bool WebRequestSetRequestHeaderAction::Equals(
809 const WebRequestAction* other) const {
810 if (!WebRequestAction::Equals(other))
812 const WebRequestSetRequestHeaderAction* casted_other =
813 static_cast<const WebRequestSetRequestHeaderAction*>(other);
814 return name_ == casted_other->name_ && value_ == casted_other->value_;
817 std::string WebRequestSetRequestHeaderAction::GetName() const {
818 return keys::kSetRequestHeaderType;
822 LinkedPtrEventResponseDelta
823 WebRequestSetRequestHeaderAction::CreateDelta(
824 const WebRequestData& request_data,
825 const std::string& extension_id,
826 const base::Time& extension_install_time) const {
827 CHECK(request_data.stage & stages());
828 LinkedPtrEventResponseDelta result(
829 new helpers::EventResponseDelta(extension_id, extension_install_time));
830 result->modified_request_headers.SetHeader(name_, value_);
835 // WebRequestRemoveRequestHeaderAction
838 WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction(
839 const std::string& name)
840 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
841 ACTION_REMOVE_REQUEST_HEADER,
842 std::numeric_limits<int>::min(),
846 WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {}
848 bool WebRequestRemoveRequestHeaderAction::Equals(
849 const WebRequestAction* other) const {
850 if (!WebRequestAction::Equals(other))
852 const WebRequestRemoveRequestHeaderAction* casted_other =
853 static_cast<const WebRequestRemoveRequestHeaderAction*>(other);
854 return name_ == casted_other->name_;
857 std::string WebRequestRemoveRequestHeaderAction::GetName() const {
858 return keys::kRemoveRequestHeaderType;
861 LinkedPtrEventResponseDelta
862 WebRequestRemoveRequestHeaderAction::CreateDelta(
863 const WebRequestData& request_data,
864 const std::string& extension_id,
865 const base::Time& extension_install_time) const {
866 CHECK(request_data.stage & stages());
867 LinkedPtrEventResponseDelta result(
868 new helpers::EventResponseDelta(extension_id, extension_install_time));
869 result->deleted_request_headers.push_back(name_);
874 // WebRequestAddResponseHeaderAction
877 WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction(
878 const std::string& name,
879 const std::string& value)
880 : WebRequestAction(ON_HEADERS_RECEIVED,
881 ACTION_ADD_RESPONSE_HEADER,
882 std::numeric_limits<int>::min(),
887 WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {}
889 bool WebRequestAddResponseHeaderAction::Equals(
890 const WebRequestAction* other) const {
891 if (!WebRequestAction::Equals(other))
893 const WebRequestAddResponseHeaderAction* casted_other =
894 static_cast<const WebRequestAddResponseHeaderAction*>(other);
895 return name_ == casted_other->name_ && value_ == casted_other->value_;
898 std::string WebRequestAddResponseHeaderAction::GetName() const {
899 return keys::kAddResponseHeaderType;
902 LinkedPtrEventResponseDelta
903 WebRequestAddResponseHeaderAction::CreateDelta(
904 const WebRequestData& request_data,
905 const std::string& extension_id,
906 const base::Time& extension_install_time) const {
907 CHECK(request_data.stage & stages());
908 const net::HttpResponseHeaders* headers =
909 request_data.original_response_headers;
911 return LinkedPtrEventResponseDelta(NULL);
913 // Don't generate the header if it exists already.
914 if (headers->HasHeaderValue(name_, value_))
915 return LinkedPtrEventResponseDelta(NULL);
917 LinkedPtrEventResponseDelta result(
918 new helpers::EventResponseDelta(extension_id, extension_install_time));
919 result->added_response_headers.push_back(make_pair(name_, value_));
924 // WebRequestRemoveResponseHeaderAction
927 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction(
928 const std::string& name,
929 const std::string& value,
931 : WebRequestAction(ON_HEADERS_RECEIVED,
932 ACTION_REMOVE_RESPONSE_HEADER,
933 std::numeric_limits<int>::min(),
937 has_value_(has_value) {}
939 WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {}
941 bool WebRequestRemoveResponseHeaderAction::Equals(
942 const WebRequestAction* other) const {
943 if (!WebRequestAction::Equals(other))
945 const WebRequestRemoveResponseHeaderAction* casted_other =
946 static_cast<const WebRequestRemoveResponseHeaderAction*>(other);
947 return name_ == casted_other->name_ && value_ == casted_other->value_ &&
948 has_value_ == casted_other->has_value_;
951 std::string WebRequestRemoveResponseHeaderAction::GetName() const {
952 return keys::kRemoveResponseHeaderType;
955 LinkedPtrEventResponseDelta
956 WebRequestRemoveResponseHeaderAction::CreateDelta(
957 const WebRequestData& request_data,
958 const std::string& extension_id,
959 const base::Time& extension_install_time) const {
960 CHECK(request_data.stage & stages());
961 const net::HttpResponseHeaders* headers =
962 request_data.original_response_headers;
964 return LinkedPtrEventResponseDelta(NULL);
966 LinkedPtrEventResponseDelta result(
967 new helpers::EventResponseDelta(extension_id, extension_install_time));
969 std::string current_value;
970 while (headers->EnumerateHeader(&iter, name_, ¤t_value)) {
972 (current_value.size() != value_.size() ||
973 !std::equal(current_value.begin(), current_value.end(),
975 base::CaseInsensitiveCompare<char>()))) {
978 result->deleted_response_headers.push_back(make_pair(name_, current_value));
984 // WebRequestIgnoreRulesAction
987 WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction(
988 int minimum_priority,
989 const std::string& ignore_tag)
990 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
991 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
995 ignore_tag_(ignore_tag) {}
997 WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {}
999 bool WebRequestIgnoreRulesAction::Equals(const WebRequestAction* other) const {
1000 if (!WebRequestAction::Equals(other))
1002 const WebRequestIgnoreRulesAction* casted_other =
1003 static_cast<const WebRequestIgnoreRulesAction*>(other);
1004 return minimum_priority() == casted_other->minimum_priority() &&
1005 ignore_tag_ == casted_other->ignore_tag_;
1008 std::string WebRequestIgnoreRulesAction::GetName() const {
1009 return keys::kIgnoreRulesType;
1012 LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta(
1013 const WebRequestData& request_data,
1014 const std::string& extension_id,
1015 const base::Time& extension_install_time) const {
1016 CHECK(request_data.stage & stages());
1017 return LinkedPtrEventResponseDelta(NULL);
1021 // WebRequestRequestCookieAction
1024 WebRequestRequestCookieAction::WebRequestRequestCookieAction(
1025 linked_ptr<RequestCookieModification> request_cookie_modification)
1026 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
1027 ACTION_MODIFY_REQUEST_COOKIE,
1028 std::numeric_limits<int>::min(),
1030 request_cookie_modification_(request_cookie_modification) {
1031 CHECK(request_cookie_modification_.get());
1034 WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
1036 bool WebRequestRequestCookieAction::Equals(
1037 const WebRequestAction* other) const {
1038 if (!WebRequestAction::Equals(other))
1040 const WebRequestRequestCookieAction* casted_other =
1041 static_cast<const WebRequestRequestCookieAction*>(other);
1042 return helpers::NullableEquals(
1043 request_cookie_modification_.get(),
1044 casted_other->request_cookie_modification_.get());
1047 std::string WebRequestRequestCookieAction::GetName() const {
1048 switch (request_cookie_modification_->type) {
1050 return keys::kAddRequestCookieType;
1052 return keys::kEditRequestCookieType;
1053 case helpers::REMOVE:
1054 return keys::kRemoveRequestCookieType;
1060 LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta(
1061 const WebRequestData& request_data,
1062 const std::string& extension_id,
1063 const base::Time& extension_install_time) const {
1064 CHECK(request_data.stage & stages());
1065 LinkedPtrEventResponseDelta result(
1066 new extension_web_request_api_helpers::EventResponseDelta(
1067 extension_id, extension_install_time));
1068 result->request_cookie_modifications.push_back(
1069 request_cookie_modification_);
1074 // WebRequestResponseCookieAction
1077 WebRequestResponseCookieAction::WebRequestResponseCookieAction(
1078 linked_ptr<ResponseCookieModification> response_cookie_modification)
1079 : WebRequestAction(ON_HEADERS_RECEIVED,
1080 ACTION_MODIFY_RESPONSE_COOKIE,
1081 std::numeric_limits<int>::min(),
1083 response_cookie_modification_(response_cookie_modification) {
1084 CHECK(response_cookie_modification_.get());
1087 WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
1089 bool WebRequestResponseCookieAction::Equals(
1090 const WebRequestAction* other) const {
1091 if (!WebRequestAction::Equals(other))
1093 const WebRequestResponseCookieAction* casted_other =
1094 static_cast<const WebRequestResponseCookieAction*>(other);
1095 return helpers::NullableEquals(
1096 response_cookie_modification_.get(),
1097 casted_other->response_cookie_modification_.get());
1100 std::string WebRequestResponseCookieAction::GetName() const {
1101 switch (response_cookie_modification_->type) {
1103 return keys::kAddResponseCookieType;
1105 return keys::kEditResponseCookieType;
1106 case helpers::REMOVE:
1107 return keys::kRemoveResponseCookieType;
1113 LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta(
1114 const WebRequestData& request_data,
1115 const std::string& extension_id,
1116 const base::Time& extension_install_time) const {
1117 CHECK(request_data.stage & stages());
1118 LinkedPtrEventResponseDelta result(
1119 new extension_web_request_api_helpers::EventResponseDelta(
1120 extension_id, extension_install_time));
1121 result->response_cookie_modifications.push_back(
1122 response_cookie_modification_);
1127 // WebRequestSendMessageToExtensionAction
1130 WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction(
1131 const std::string& message)
1132 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
1133 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
1134 ACTION_SEND_MESSAGE_TO_EXTENSION,
1135 std::numeric_limits<int>::min(),
1137 message_(message) {}
1139 WebRequestSendMessageToExtensionAction::
1140 ~WebRequestSendMessageToExtensionAction() {}
1142 bool WebRequestSendMessageToExtensionAction::Equals(
1143 const WebRequestAction* other) const {
1144 if (!WebRequestAction::Equals(other))
1146 const WebRequestSendMessageToExtensionAction* casted_other =
1147 static_cast<const WebRequestSendMessageToExtensionAction*>(other);
1148 return message_ == casted_other->message_;
1151 std::string WebRequestSendMessageToExtensionAction::GetName() const {
1152 return keys::kSendMessageToExtensionType;
1155 LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta(
1156 const WebRequestData& request_data,
1157 const std::string& extension_id,
1158 const base::Time& extension_install_time) const {
1159 CHECK(request_data.stage & stages());
1160 LinkedPtrEventResponseDelta result(
1161 new extension_web_request_api_helpers::EventResponseDelta(
1162 extension_id, extension_install_time));
1163 result->messages_to_extension.insert(message_);
1167 } // namespace extensions