Enable Enterprise enrollment on desktop builds.
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_webrequest / webrequest_action.cc
blob739d0744b955c08569db4a8f5bf9f501b75c6541
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"
7 #include <limits>
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 "content/public/common/url_constants.h"
22 #include "extensions/browser/info_map.h"
23 #include "extensions/common/error_utils.h"
24 #include "extensions/common/extension.h"
25 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
26 #include "net/url_request/url_request.h"
27 #include "third_party/re2/re2/re2.h"
29 namespace extensions {
31 namespace helpers = extension_web_request_api_helpers;
32 namespace keys = declarative_webrequest_constants;
34 namespace {
35 // Error messages.
36 const char kIgnoreRulesRequiresParameterError[] =
37 "IgnoreRules requires at least one parameter.";
39 const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh"
40 "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==";
41 const char kEmptyDocumentUrl[] = "data:text/html,";
43 #define INPUT_FORMAT_VALIDATE(test) do { \
44 if (!(test)) { \
45 *bad_message = true; \
46 return scoped_refptr<const WebRequestAction>(NULL); \
47 } \
48 } while (0)
50 scoped_ptr<helpers::RequestCookie> ParseRequestCookie(
51 const base::DictionaryValue* dict) {
52 scoped_ptr<helpers::RequestCookie> result(new helpers::RequestCookie);
53 std::string tmp;
54 if (dict->GetString(keys::kNameKey, &tmp))
55 result->name.reset(new std::string(tmp));
56 if (dict->GetString(keys::kValueKey, &tmp))
57 result->value.reset(new std::string(tmp));
58 return result.Pass();
61 void ParseResponseCookieImpl(const base::DictionaryValue* dict,
62 helpers::ResponseCookie* cookie) {
63 std::string string_tmp;
64 int int_tmp = 0;
65 bool bool_tmp = false;
66 if (dict->GetString(keys::kNameKey, &string_tmp))
67 cookie->name.reset(new std::string(string_tmp));
68 if (dict->GetString(keys::kValueKey, &string_tmp))
69 cookie->value.reset(new std::string(string_tmp));
70 if (dict->GetString(keys::kExpiresKey, &string_tmp))
71 cookie->expires.reset(new std::string(string_tmp));
72 if (dict->GetInteger(keys::kMaxAgeKey, &int_tmp))
73 cookie->max_age.reset(new int(int_tmp));
74 if (dict->GetString(keys::kDomainKey, &string_tmp))
75 cookie->domain.reset(new std::string(string_tmp));
76 if (dict->GetString(keys::kPathKey, &string_tmp))
77 cookie->path.reset(new std::string(string_tmp));
78 if (dict->GetBoolean(keys::kSecureKey, &bool_tmp))
79 cookie->secure.reset(new bool(bool_tmp));
80 if (dict->GetBoolean(keys::kHttpOnlyKey, &bool_tmp))
81 cookie->http_only.reset(new bool(bool_tmp));
84 scoped_ptr<helpers::ResponseCookie> ParseResponseCookie(
85 const base::DictionaryValue* dict) {
86 scoped_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie);
87 ParseResponseCookieImpl(dict, result.get());
88 return result.Pass();
91 scoped_ptr<helpers::FilterResponseCookie> ParseFilterResponseCookie(
92 const base::DictionaryValue* dict) {
93 scoped_ptr<helpers::FilterResponseCookie> result(
94 new helpers::FilterResponseCookie);
95 ParseResponseCookieImpl(dict, result.get());
97 int int_tmp = 0;
98 bool bool_tmp = false;
99 if (dict->GetInteger(keys::kAgeUpperBoundKey, &int_tmp))
100 result->age_upper_bound.reset(new int(int_tmp));
101 if (dict->GetInteger(keys::kAgeLowerBoundKey, &int_tmp))
102 result->age_lower_bound.reset(new int(int_tmp));
103 if (dict->GetBoolean(keys::kSessionCookieKey, &bool_tmp))
104 result->session_cookie.reset(new bool(bool_tmp));
105 return result.Pass();
108 // Helper function for WebRequestActions that can be instantiated by just
109 // calling the constructor.
110 template <class T>
111 scoped_refptr<const WebRequestAction> CallConstructorFactoryMethod(
112 const std::string& instance_type,
113 const base::Value* value,
114 std::string* error,
115 bool* bad_message) {
116 return scoped_refptr<const WebRequestAction>(new T);
119 scoped_refptr<const WebRequestAction> CreateRedirectRequestAction(
120 const std::string& instance_type,
121 const base::Value* value,
122 std::string* error,
123 bool* bad_message) {
124 const base::DictionaryValue* dict = NULL;
125 CHECK(value->GetAsDictionary(&dict));
126 std::string redirect_url_string;
127 INPUT_FORMAT_VALIDATE(
128 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string));
129 GURL redirect_url(redirect_url_string);
130 return scoped_refptr<const WebRequestAction>(
131 new WebRequestRedirectAction(redirect_url));
134 scoped_refptr<const WebRequestAction> CreateRedirectRequestByRegExAction(
135 const std::string& instance_type,
136 const base::Value* value,
137 std::string* error,
138 bool* bad_message) {
139 const base::DictionaryValue* dict = NULL;
140 CHECK(value->GetAsDictionary(&dict));
141 std::string from;
142 std::string to;
143 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from));
144 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to));
146 to = WebRequestRedirectByRegExAction::PerlToRe2Style(to);
148 RE2::Options options;
149 options.set_case_sensitive(false);
150 scoped_ptr<RE2> from_pattern(new RE2(from, options));
152 if (!from_pattern->ok()) {
153 *error = "Invalid pattern '" + from + "' -> '" + to + "'";
154 return scoped_refptr<const WebRequestAction>(NULL);
156 return scoped_refptr<const WebRequestAction>(
157 new WebRequestRedirectByRegExAction(from_pattern.Pass(), to));
160 scoped_refptr<const WebRequestAction> CreateSetRequestHeaderAction(
161 const std::string& instance_type,
162 const base::Value* json_value,
163 std::string* error,
164 bool* bad_message) {
165 const base::DictionaryValue* dict = NULL;
166 CHECK(json_value->GetAsDictionary(&dict));
167 std::string name;
168 std::string value;
169 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
170 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
171 if (!helpers::IsValidHeaderName(name)) {
172 *error = extension_web_request_api_constants::kInvalidHeaderName;
173 return scoped_refptr<const WebRequestAction>(NULL);
175 if (!helpers::IsValidHeaderValue(value)) {
176 *error = ErrorUtils::FormatErrorMessage(
177 extension_web_request_api_constants::kInvalidHeaderValue, name);
178 return scoped_refptr<const WebRequestAction>(NULL);
180 return scoped_refptr<const WebRequestAction>(
181 new WebRequestSetRequestHeaderAction(name, value));
184 scoped_refptr<const WebRequestAction> CreateRemoveRequestHeaderAction(
185 const std::string& instance_type,
186 const base::Value* value,
187 std::string* error,
188 bool* bad_message) {
189 const base::DictionaryValue* dict = NULL;
190 CHECK(value->GetAsDictionary(&dict));
191 std::string name;
192 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
193 if (!helpers::IsValidHeaderName(name)) {
194 *error = extension_web_request_api_constants::kInvalidHeaderName;
195 return scoped_refptr<const WebRequestAction>(NULL);
197 return scoped_refptr<const WebRequestAction>(
198 new WebRequestRemoveRequestHeaderAction(name));
201 scoped_refptr<const WebRequestAction> CreateAddResponseHeaderAction(
202 const std::string& instance_type,
203 const base::Value* json_value,
204 std::string* error,
205 bool* bad_message) {
206 const base::DictionaryValue* dict = NULL;
207 CHECK(json_value->GetAsDictionary(&dict));
208 std::string name;
209 std::string value;
210 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
211 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
212 if (!helpers::IsValidHeaderName(name)) {
213 *error = extension_web_request_api_constants::kInvalidHeaderName;
214 return scoped_refptr<const WebRequestAction>(NULL);
216 if (!helpers::IsValidHeaderValue(value)) {
217 *error = ErrorUtils::FormatErrorMessage(
218 extension_web_request_api_constants::kInvalidHeaderValue, name);
219 return scoped_refptr<const WebRequestAction>(NULL);
221 return scoped_refptr<const WebRequestAction>(
222 new WebRequestAddResponseHeaderAction(name, value));
225 scoped_refptr<const WebRequestAction> CreateRemoveResponseHeaderAction(
226 const std::string& instance_type,
227 const base::Value* json_value,
228 std::string* error,
229 bool* bad_message) {
230 const base::DictionaryValue* dict = NULL;
231 CHECK(json_value->GetAsDictionary(&dict));
232 std::string name;
233 std::string value;
234 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
235 bool has_value = dict->GetString(keys::kValueKey, &value);
236 if (!helpers::IsValidHeaderName(name)) {
237 *error = extension_web_request_api_constants::kInvalidHeaderName;
238 return scoped_refptr<const WebRequestAction>(NULL);
240 if (has_value && !helpers::IsValidHeaderValue(value)) {
241 *error = ErrorUtils::FormatErrorMessage(
242 extension_web_request_api_constants::kInvalidHeaderValue, name);
243 return scoped_refptr<const WebRequestAction>(NULL);
245 return scoped_refptr<const WebRequestAction>(
246 new WebRequestRemoveResponseHeaderAction(name, value, has_value));
249 scoped_refptr<const WebRequestAction> CreateIgnoreRulesAction(
250 const std::string& instance_type,
251 const base::Value* value,
252 std::string* error,
253 bool* bad_message) {
254 const base::DictionaryValue* dict = NULL;
255 CHECK(value->GetAsDictionary(&dict));
256 bool has_parameter = false;
257 int minimum_priority = std::numeric_limits<int>::min();
258 std::string ignore_tag;
259 if (dict->HasKey(keys::kLowerPriorityThanKey)) {
260 INPUT_FORMAT_VALIDATE(
261 dict->GetInteger(keys::kLowerPriorityThanKey, &minimum_priority));
262 has_parameter = true;
264 if (dict->HasKey(keys::kHasTagKey)) {
265 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kHasTagKey, &ignore_tag));
266 has_parameter = true;
268 if (!has_parameter) {
269 *error = kIgnoreRulesRequiresParameterError;
270 return scoped_refptr<const WebRequestAction>(NULL);
272 return scoped_refptr<const WebRequestAction>(
273 new WebRequestIgnoreRulesAction(minimum_priority, ignore_tag));
276 scoped_refptr<const WebRequestAction> CreateRequestCookieAction(
277 const std::string& instance_type,
278 const base::Value* value,
279 std::string* error,
280 bool* bad_message) {
281 using extension_web_request_api_helpers::RequestCookieModification;
283 const base::DictionaryValue* dict = NULL;
284 CHECK(value->GetAsDictionary(&dict));
286 linked_ptr<RequestCookieModification> modification(
287 new RequestCookieModification);
289 // Get modification type.
290 if (instance_type == keys::kAddRequestCookieType)
291 modification->type = helpers::ADD;
292 else if (instance_type == keys::kEditRequestCookieType)
293 modification->type = helpers::EDIT;
294 else if (instance_type == keys::kRemoveRequestCookieType)
295 modification->type = helpers::REMOVE;
296 else
297 INPUT_FORMAT_VALIDATE(false);
299 // Get filter.
300 if (modification->type == helpers::EDIT ||
301 modification->type == helpers::REMOVE) {
302 const base::DictionaryValue* filter = NULL;
303 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
304 modification->filter = ParseRequestCookie(filter);
307 // Get new value.
308 if (modification->type == helpers::ADD) {
309 const base::DictionaryValue* value = NULL;
310 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
311 modification->modification = ParseRequestCookie(value);
312 } else if (modification->type == helpers::EDIT) {
313 const base::DictionaryValue* value = NULL;
314 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
315 modification->modification = ParseRequestCookie(value);
318 return scoped_refptr<const WebRequestAction>(
319 new WebRequestRequestCookieAction(modification));
322 scoped_refptr<const WebRequestAction> CreateResponseCookieAction(
323 const std::string& instance_type,
324 const base::Value* value,
325 std::string* error,
326 bool* bad_message) {
327 using extension_web_request_api_helpers::ResponseCookieModification;
329 const base::DictionaryValue* dict = NULL;
330 CHECK(value->GetAsDictionary(&dict));
332 linked_ptr<ResponseCookieModification> modification(
333 new ResponseCookieModification);
335 // Get modification type.
336 if (instance_type == keys::kAddResponseCookieType)
337 modification->type = helpers::ADD;
338 else if (instance_type == keys::kEditResponseCookieType)
339 modification->type = helpers::EDIT;
340 else if (instance_type == keys::kRemoveResponseCookieType)
341 modification->type = helpers::REMOVE;
342 else
343 INPUT_FORMAT_VALIDATE(false);
345 // Get filter.
346 if (modification->type == helpers::EDIT ||
347 modification->type == helpers::REMOVE) {
348 const base::DictionaryValue* filter = NULL;
349 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
350 modification->filter = ParseFilterResponseCookie(filter);
353 // Get new value.
354 if (modification->type == helpers::ADD) {
355 const base::DictionaryValue* value = NULL;
356 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
357 modification->modification = ParseResponseCookie(value);
358 } else if (modification->type == helpers::EDIT) {
359 const base::DictionaryValue* value = NULL;
360 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
361 modification->modification = ParseResponseCookie(value);
364 return scoped_refptr<const WebRequestAction>(
365 new WebRequestResponseCookieAction(modification));
368 scoped_refptr<const WebRequestAction> CreateSendMessageToExtensionAction(
369 const std::string& name,
370 const base::Value* value,
371 std::string* error,
372 bool* bad_message) {
373 const base::DictionaryValue* dict = NULL;
374 CHECK(value->GetAsDictionary(&dict));
375 std::string message;
376 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kMessageKey, &message));
377 return scoped_refptr<const WebRequestAction>(
378 new WebRequestSendMessageToExtensionAction(message));
381 struct WebRequestActionFactory {
382 DedupingFactory<WebRequestAction> factory;
384 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);
457 base::LazyInstance<WebRequestActionFactory>::Leaky
458 g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER;
460 } // namespace
463 // WebRequestAction
466 WebRequestAction::~WebRequestAction() {}
468 bool WebRequestAction::Equals(const WebRequestAction* other) const {
469 return type() == other->type();
472 bool WebRequestAction::HasPermission(const InfoMap* extension_info_map,
473 const std::string& extension_id,
474 const net::URLRequest* request,
475 bool crosses_incognito) const {
476 if (WebRequestPermissions::HideRequest(extension_info_map, request))
477 return false;
479 // In unit tests we don't have an extension_info_map object here and skip host
480 // permission checks.
481 if (!extension_info_map)
482 return true;
484 WebRequestPermissions::HostPermissionsCheck permission_check =
485 WebRequestPermissions::REQUIRE_ALL_URLS;
486 switch (host_permissions_strategy()) {
487 case STRATEGY_DEFAULT: // Default value is already set.
488 break;
489 case STRATEGY_NONE:
490 permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST;
491 break;
492 case STRATEGY_HOST:
493 permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION;
494 break;
496 return WebRequestPermissions::CanExtensionAccessURL(
497 extension_info_map, extension_id, request->url(), crosses_incognito,
498 permission_check);
501 // static
502 scoped_refptr<const WebRequestAction> WebRequestAction::Create(
503 const Extension* extension,
504 const base::Value& json_action,
505 std::string* error,
506 bool* bad_message) {
507 *error = "";
508 *bad_message = false;
510 const base::DictionaryValue* action_dict = NULL;
511 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
513 std::string instance_type;
514 INPUT_FORMAT_VALIDATE(
515 action_dict->GetString(keys::kInstanceTypeKey, &instance_type));
517 WebRequestActionFactory& factory = g_web_request_action_factory.Get();
518 return factory.factory.Instantiate(
519 instance_type, action_dict, error, bad_message);
522 void WebRequestAction::Apply(const std::string& extension_id,
523 base::Time extension_install_time,
524 ApplyInfo* apply_info) const {
525 if (!HasPermission(apply_info->extension_info_map, extension_id,
526 apply_info->request_data.request,
527 apply_info->crosses_incognito))
528 return;
529 if (stages() & apply_info->request_data.stage) {
530 LinkedPtrEventResponseDelta delta = CreateDelta(
531 apply_info->request_data, extension_id, extension_install_time);
532 if (delta.get())
533 apply_info->deltas->push_back(delta);
534 if (type() == WebRequestAction::ACTION_IGNORE_RULES) {
535 const WebRequestIgnoreRulesAction* ignore_action =
536 static_cast<const WebRequestIgnoreRulesAction*>(this);
537 if (!ignore_action->ignore_tag().empty())
538 apply_info->ignored_tags->insert(ignore_action->ignore_tag());
543 WebRequestAction::WebRequestAction(int stages,
544 Type type,
545 int minimum_priority,
546 HostPermissionsStrategy strategy)
547 : stages_(stages),
548 type_(type),
549 minimum_priority_(minimum_priority),
550 host_permissions_strategy_(strategy) {}
553 // WebRequestCancelAction
556 WebRequestCancelAction::WebRequestCancelAction()
557 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
558 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
559 ACTION_CANCEL_REQUEST,
560 std::numeric_limits<int>::min(),
561 STRATEGY_NONE) {}
563 WebRequestCancelAction::~WebRequestCancelAction() {}
565 std::string WebRequestCancelAction::GetName() const {
566 return keys::kCancelRequestType;
569 LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta(
570 const WebRequestData& request_data,
571 const std::string& extension_id,
572 const base::Time& extension_install_time) const {
573 CHECK(request_data.stage & stages());
574 LinkedPtrEventResponseDelta result(
575 new helpers::EventResponseDelta(extension_id, extension_install_time));
576 result->cancel = true;
577 return result;
581 // WebRequestRedirectAction
584 WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url)
585 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
586 ACTION_REDIRECT_REQUEST,
587 std::numeric_limits<int>::min(),
588 STRATEGY_DEFAULT),
589 redirect_url_(redirect_url) {}
591 WebRequestRedirectAction::~WebRequestRedirectAction() {}
593 bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const {
594 return WebRequestAction::Equals(other) &&
595 redirect_url_ ==
596 static_cast<const WebRequestRedirectAction*>(other)->redirect_url_;
599 std::string WebRequestRedirectAction::GetName() const {
600 return keys::kRedirectRequestType;
603 LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta(
604 const WebRequestData& request_data,
605 const std::string& extension_id,
606 const base::Time& extension_install_time) const {
607 CHECK(request_data.stage & stages());
608 if (request_data.request->url() == redirect_url_)
609 return LinkedPtrEventResponseDelta(NULL);
610 LinkedPtrEventResponseDelta result(
611 new helpers::EventResponseDelta(extension_id, extension_install_time));
612 result->new_url = redirect_url_;
613 return result;
617 // WebRequestRedirectToTransparentImageAction
620 WebRequestRedirectToTransparentImageAction::
621 WebRequestRedirectToTransparentImageAction()
622 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
623 ACTION_REDIRECT_TO_TRANSPARENT_IMAGE,
624 std::numeric_limits<int>::min(),
625 STRATEGY_NONE) {}
627 WebRequestRedirectToTransparentImageAction::
628 ~WebRequestRedirectToTransparentImageAction() {}
630 std::string WebRequestRedirectToTransparentImageAction::GetName() const {
631 return keys::kRedirectToTransparentImageType;
634 LinkedPtrEventResponseDelta
635 WebRequestRedirectToTransparentImageAction::CreateDelta(
636 const WebRequestData& request_data,
637 const std::string& extension_id,
638 const base::Time& extension_install_time) const {
639 CHECK(request_data.stage & stages());
640 LinkedPtrEventResponseDelta result(
641 new helpers::EventResponseDelta(extension_id, extension_install_time));
642 result->new_url = GURL(kTransparentImageUrl);
643 return result;
647 // WebRequestRedirectToEmptyDocumentAction
650 WebRequestRedirectToEmptyDocumentAction::
651 WebRequestRedirectToEmptyDocumentAction()
652 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
653 ACTION_REDIRECT_TO_EMPTY_DOCUMENT,
654 std::numeric_limits<int>::min(),
655 STRATEGY_NONE) {}
657 WebRequestRedirectToEmptyDocumentAction::
658 ~WebRequestRedirectToEmptyDocumentAction() {}
660 std::string WebRequestRedirectToEmptyDocumentAction::GetName() const {
661 return keys::kRedirectToEmptyDocumentType;
664 LinkedPtrEventResponseDelta
665 WebRequestRedirectToEmptyDocumentAction::CreateDelta(
666 const WebRequestData& request_data,
667 const std::string& extension_id,
668 const base::Time& extension_install_time) const {
669 CHECK(request_data.stage & stages());
670 LinkedPtrEventResponseDelta result(
671 new helpers::EventResponseDelta(extension_id, extension_install_time));
672 result->new_url = GURL(kEmptyDocumentUrl);
673 return result;
677 // WebRequestRedirectByRegExAction
680 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction(
681 scoped_ptr<RE2> from_pattern,
682 const std::string& to_pattern)
683 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
684 ACTION_REDIRECT_BY_REGEX_DOCUMENT,
685 std::numeric_limits<int>::min(),
686 STRATEGY_DEFAULT),
687 from_pattern_(from_pattern.Pass()),
688 to_pattern_(to_pattern.data(), to_pattern.size()) {}
690 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
692 // About the syntax of the two languages:
694 // ICU (Perl) states:
695 // $n The text of capture group n will be substituted for $n. n must be >= 0
696 // and not greater than the number of capture groups. A $ not followed by a
697 // digit has no special meaning, and will appear in the substitution text
698 // as itself, a $.
699 // \ Treat the following character as a literal, suppressing any special
700 // meaning. Backslash escaping in substitution text is only required for
701 // '$' and '\', but may be used on any other character without bad effects.
703 // RE2, derived from RE2::Rewrite()
704 // \ May only be followed by a digit or another \. If followed by a single
705 // digit, both characters represent the respective capture group. If followed
706 // by another \, it is used as an escape sequence.
708 // static
709 std::string WebRequestRedirectByRegExAction::PerlToRe2Style(
710 const std::string& perl) {
711 std::string::const_iterator i = perl.begin();
712 std::string result;
713 while (i != perl.end()) {
714 if (*i == '$') {
715 ++i;
716 if (i == perl.end()) {
717 result += '$';
718 return result;
719 } else if (isdigit(*i)) {
720 result += '\\';
721 result += *i;
722 } else {
723 result += '$';
724 result += *i;
726 } else if (*i == '\\') {
727 ++i;
728 if (i == perl.end()) {
729 result += '\\';
730 } else if (*i == '$') {
731 result += '$';
732 } else if (*i == '\\') {
733 result += "\\\\";
734 } else {
735 result += *i;
737 } else {
738 result += *i;
740 ++i;
742 return result;
745 bool WebRequestRedirectByRegExAction::Equals(
746 const WebRequestAction* other) const {
747 if (!WebRequestAction::Equals(other))
748 return false;
749 const WebRequestRedirectByRegExAction* casted_other =
750 static_cast<const WebRequestRedirectByRegExAction*>(other);
751 return from_pattern_->pattern() == casted_other->from_pattern_->pattern() &&
752 to_pattern_ == casted_other->to_pattern_;
755 std::string WebRequestRedirectByRegExAction::GetName() const {
756 return keys::kRedirectByRegExType;
759 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta(
760 const WebRequestData& request_data,
761 const std::string& extension_id,
762 const base::Time& extension_install_time) const {
763 CHECK(request_data.stage & stages());
764 CHECK(from_pattern_.get());
766 const std::string& old_url = request_data.request->url().spec();
767 std::string new_url = old_url;
768 if (!RE2::Replace(&new_url, *from_pattern_, to_pattern_) ||
769 new_url == old_url) {
770 return LinkedPtrEventResponseDelta(NULL);
773 LinkedPtrEventResponseDelta result(
774 new extension_web_request_api_helpers::EventResponseDelta(
775 extension_id, extension_install_time));
776 result->new_url = GURL(new_url);
777 return result;
781 // WebRequestSetRequestHeaderAction
784 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction(
785 const std::string& name,
786 const std::string& value)
787 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
788 ACTION_SET_REQUEST_HEADER,
789 std::numeric_limits<int>::min(),
790 STRATEGY_DEFAULT),
791 name_(name),
792 value_(value) {}
794 WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {}
796 bool WebRequestSetRequestHeaderAction::Equals(
797 const WebRequestAction* other) const {
798 if (!WebRequestAction::Equals(other))
799 return false;
800 const WebRequestSetRequestHeaderAction* casted_other =
801 static_cast<const WebRequestSetRequestHeaderAction*>(other);
802 return name_ == casted_other->name_ && value_ == casted_other->value_;
805 std::string WebRequestSetRequestHeaderAction::GetName() const {
806 return keys::kSetRequestHeaderType;
810 LinkedPtrEventResponseDelta
811 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 LinkedPtrEventResponseDelta result(
817 new helpers::EventResponseDelta(extension_id, extension_install_time));
818 result->modified_request_headers.SetHeader(name_, value_);
819 return result;
823 // WebRequestRemoveRequestHeaderAction
826 WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction(
827 const std::string& name)
828 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
829 ACTION_REMOVE_REQUEST_HEADER,
830 std::numeric_limits<int>::min(),
831 STRATEGY_DEFAULT),
832 name_(name) {}
834 WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {}
836 bool WebRequestRemoveRequestHeaderAction::Equals(
837 const WebRequestAction* other) const {
838 if (!WebRequestAction::Equals(other))
839 return false;
840 const WebRequestRemoveRequestHeaderAction* casted_other =
841 static_cast<const WebRequestRemoveRequestHeaderAction*>(other);
842 return name_ == casted_other->name_;
845 std::string WebRequestRemoveRequestHeaderAction::GetName() const {
846 return keys::kRemoveRequestHeaderType;
849 LinkedPtrEventResponseDelta
850 WebRequestRemoveRequestHeaderAction::CreateDelta(
851 const WebRequestData& request_data,
852 const std::string& extension_id,
853 const base::Time& extension_install_time) const {
854 CHECK(request_data.stage & stages());
855 LinkedPtrEventResponseDelta result(
856 new helpers::EventResponseDelta(extension_id, extension_install_time));
857 result->deleted_request_headers.push_back(name_);
858 return result;
862 // WebRequestAddResponseHeaderAction
865 WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction(
866 const std::string& name,
867 const std::string& value)
868 : WebRequestAction(ON_HEADERS_RECEIVED,
869 ACTION_ADD_RESPONSE_HEADER,
870 std::numeric_limits<int>::min(),
871 STRATEGY_DEFAULT),
872 name_(name),
873 value_(value) {}
875 WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {}
877 bool WebRequestAddResponseHeaderAction::Equals(
878 const WebRequestAction* other) const {
879 if (!WebRequestAction::Equals(other))
880 return false;
881 const WebRequestAddResponseHeaderAction* casted_other =
882 static_cast<const WebRequestAddResponseHeaderAction*>(other);
883 return name_ == casted_other->name_ && value_ == casted_other->value_;
886 std::string WebRequestAddResponseHeaderAction::GetName() const {
887 return keys::kAddResponseHeaderType;
890 LinkedPtrEventResponseDelta
891 WebRequestAddResponseHeaderAction::CreateDelta(
892 const WebRequestData& request_data,
893 const std::string& extension_id,
894 const base::Time& extension_install_time) const {
895 CHECK(request_data.stage & stages());
896 const net::HttpResponseHeaders* headers =
897 request_data.original_response_headers;
898 if (!headers)
899 return LinkedPtrEventResponseDelta(NULL);
901 // Don't generate the header if it exists already.
902 if (headers->HasHeaderValue(name_, value_))
903 return LinkedPtrEventResponseDelta(NULL);
905 LinkedPtrEventResponseDelta result(
906 new helpers::EventResponseDelta(extension_id, extension_install_time));
907 result->added_response_headers.push_back(make_pair(name_, value_));
908 return result;
912 // WebRequestRemoveResponseHeaderAction
915 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction(
916 const std::string& name,
917 const std::string& value,
918 bool has_value)
919 : WebRequestAction(ON_HEADERS_RECEIVED,
920 ACTION_REMOVE_RESPONSE_HEADER,
921 std::numeric_limits<int>::min(),
922 STRATEGY_DEFAULT),
923 name_(name),
924 value_(value),
925 has_value_(has_value) {}
927 WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {}
929 bool WebRequestRemoveResponseHeaderAction::Equals(
930 const WebRequestAction* other) const {
931 if (!WebRequestAction::Equals(other))
932 return false;
933 const WebRequestRemoveResponseHeaderAction* casted_other =
934 static_cast<const WebRequestRemoveResponseHeaderAction*>(other);
935 return name_ == casted_other->name_ && value_ == casted_other->value_ &&
936 has_value_ == casted_other->has_value_;
939 std::string WebRequestRemoveResponseHeaderAction::GetName() const {
940 return keys::kRemoveResponseHeaderType;
943 LinkedPtrEventResponseDelta
944 WebRequestRemoveResponseHeaderAction::CreateDelta(
945 const WebRequestData& request_data,
946 const std::string& extension_id,
947 const base::Time& extension_install_time) const {
948 CHECK(request_data.stage & stages());
949 const net::HttpResponseHeaders* headers =
950 request_data.original_response_headers;
951 if (!headers)
952 return LinkedPtrEventResponseDelta(NULL);
954 LinkedPtrEventResponseDelta result(
955 new helpers::EventResponseDelta(extension_id, extension_install_time));
956 void* iter = NULL;
957 std::string current_value;
958 while (headers->EnumerateHeader(&iter, name_, &current_value)) {
959 if (has_value_ &&
960 (current_value.size() != value_.size() ||
961 !std::equal(current_value.begin(), current_value.end(),
962 value_.begin(),
963 base::CaseInsensitiveCompare<char>()))) {
964 continue;
966 result->deleted_response_headers.push_back(make_pair(name_, current_value));
968 return result;
972 // WebRequestIgnoreRulesAction
975 WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction(
976 int minimum_priority,
977 const std::string& ignore_tag)
978 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
979 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
980 ACTION_IGNORE_RULES,
981 minimum_priority,
982 STRATEGY_NONE),
983 ignore_tag_(ignore_tag) {}
985 WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {}
987 bool WebRequestIgnoreRulesAction::Equals(const WebRequestAction* other) const {
988 if (!WebRequestAction::Equals(other))
989 return false;
990 const WebRequestIgnoreRulesAction* casted_other =
991 static_cast<const WebRequestIgnoreRulesAction*>(other);
992 return minimum_priority() == casted_other->minimum_priority() &&
993 ignore_tag_ == casted_other->ignore_tag_;
996 std::string WebRequestIgnoreRulesAction::GetName() const {
997 return keys::kIgnoreRulesType;
1000 LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta(
1001 const WebRequestData& request_data,
1002 const std::string& extension_id,
1003 const base::Time& extension_install_time) const {
1004 CHECK(request_data.stage & stages());
1005 return LinkedPtrEventResponseDelta(NULL);
1009 // WebRequestRequestCookieAction
1012 WebRequestRequestCookieAction::WebRequestRequestCookieAction(
1013 linked_ptr<RequestCookieModification> request_cookie_modification)
1014 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
1015 ACTION_MODIFY_REQUEST_COOKIE,
1016 std::numeric_limits<int>::min(),
1017 STRATEGY_DEFAULT),
1018 request_cookie_modification_(request_cookie_modification) {
1019 CHECK(request_cookie_modification_.get());
1022 WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
1024 bool WebRequestRequestCookieAction::Equals(
1025 const WebRequestAction* other) const {
1026 if (!WebRequestAction::Equals(other))
1027 return false;
1028 const WebRequestRequestCookieAction* casted_other =
1029 static_cast<const WebRequestRequestCookieAction*>(other);
1030 return helpers::NullableEquals(
1031 request_cookie_modification_.get(),
1032 casted_other->request_cookie_modification_.get());
1035 std::string WebRequestRequestCookieAction::GetName() const {
1036 switch (request_cookie_modification_->type) {
1037 case helpers::ADD:
1038 return keys::kAddRequestCookieType;
1039 case helpers::EDIT:
1040 return keys::kEditRequestCookieType;
1041 case helpers::REMOVE:
1042 return keys::kRemoveRequestCookieType;
1044 NOTREACHED();
1045 return "";
1048 LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta(
1049 const WebRequestData& request_data,
1050 const std::string& extension_id,
1051 const base::Time& extension_install_time) const {
1052 CHECK(request_data.stage & stages());
1053 LinkedPtrEventResponseDelta result(
1054 new extension_web_request_api_helpers::EventResponseDelta(
1055 extension_id, extension_install_time));
1056 result->request_cookie_modifications.push_back(
1057 request_cookie_modification_);
1058 return result;
1062 // WebRequestResponseCookieAction
1065 WebRequestResponseCookieAction::WebRequestResponseCookieAction(
1066 linked_ptr<ResponseCookieModification> response_cookie_modification)
1067 : WebRequestAction(ON_HEADERS_RECEIVED,
1068 ACTION_MODIFY_RESPONSE_COOKIE,
1069 std::numeric_limits<int>::min(),
1070 STRATEGY_DEFAULT),
1071 response_cookie_modification_(response_cookie_modification) {
1072 CHECK(response_cookie_modification_.get());
1075 WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
1077 bool WebRequestResponseCookieAction::Equals(
1078 const WebRequestAction* other) const {
1079 if (!WebRequestAction::Equals(other))
1080 return false;
1081 const WebRequestResponseCookieAction* casted_other =
1082 static_cast<const WebRequestResponseCookieAction*>(other);
1083 return helpers::NullableEquals(
1084 response_cookie_modification_.get(),
1085 casted_other->response_cookie_modification_.get());
1088 std::string WebRequestResponseCookieAction::GetName() const {
1089 switch (response_cookie_modification_->type) {
1090 case helpers::ADD:
1091 return keys::kAddResponseCookieType;
1092 case helpers::EDIT:
1093 return keys::kEditResponseCookieType;
1094 case helpers::REMOVE:
1095 return keys::kRemoveResponseCookieType;
1097 NOTREACHED();
1098 return "";
1101 LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta(
1102 const WebRequestData& request_data,
1103 const std::string& extension_id,
1104 const base::Time& extension_install_time) const {
1105 CHECK(request_data.stage & stages());
1106 LinkedPtrEventResponseDelta result(
1107 new extension_web_request_api_helpers::EventResponseDelta(
1108 extension_id, extension_install_time));
1109 result->response_cookie_modifications.push_back(
1110 response_cookie_modification_);
1111 return result;
1115 // WebRequestSendMessageToExtensionAction
1118 WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction(
1119 const std::string& message)
1120 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
1121 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
1122 ACTION_SEND_MESSAGE_TO_EXTENSION,
1123 std::numeric_limits<int>::min(),
1124 STRATEGY_HOST),
1125 message_(message) {}
1127 WebRequestSendMessageToExtensionAction::
1128 ~WebRequestSendMessageToExtensionAction() {}
1130 bool WebRequestSendMessageToExtensionAction::Equals(
1131 const WebRequestAction* other) const {
1132 if (!WebRequestAction::Equals(other))
1133 return false;
1134 const WebRequestSendMessageToExtensionAction* casted_other =
1135 static_cast<const WebRequestSendMessageToExtensionAction*>(other);
1136 return message_ == casted_other->message_;
1139 std::string WebRequestSendMessageToExtensionAction::GetName() const {
1140 return keys::kSendMessageToExtensionType;
1143 LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta(
1144 const WebRequestData& request_data,
1145 const std::string& extension_id,
1146 const base::Time& extension_install_time) const {
1147 CHECK(request_data.stage & stages());
1148 LinkedPtrEventResponseDelta result(
1149 new extension_web_request_api_helpers::EventResponseDelta(
1150 extension_id, extension_install_time));
1151 result->messages_to_extension.insert(message_);
1152 return result;
1155 } // namespace extensions