Update {virtual,override,final} to follow C++11 style.
[chromium-blink-merge.git] / extensions / browser / api / declarative_webrequest / webrequest_action.cc
blob6d79227fdee71e6ad042f04c83f75a6e2d63a7c1
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 "extensions/browser/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 "content/public/browser/resource_request_info.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_permissions.h"
23 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.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/http/http_util.h"
29 #include "net/url_request/url_request.h"
30 #include "third_party/re2/re2/re2.h"
32 using content::ResourceRequestInfo;
34 namespace extensions {
36 namespace helpers = extension_web_request_api_helpers;
37 namespace keys = declarative_webrequest_constants;
39 namespace {
40 // Error messages.
41 const char kIgnoreRulesRequiresParameterError[] =
42 "IgnoreRules requires at least one parameter.";
44 const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh"
45 "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==";
46 const char kEmptyDocumentUrl[] = "data:text/html,";
48 #define INPUT_FORMAT_VALIDATE(test) do { \
49 if (!(test)) { \
50 *bad_message = true; \
51 return scoped_refptr<const WebRequestAction>(NULL); \
52 } \
53 } while (0)
55 scoped_ptr<helpers::RequestCookie> ParseRequestCookie(
56 const base::DictionaryValue* dict) {
57 scoped_ptr<helpers::RequestCookie> result(new helpers::RequestCookie);
58 std::string tmp;
59 if (dict->GetString(keys::kNameKey, &tmp))
60 result->name.reset(new std::string(tmp));
61 if (dict->GetString(keys::kValueKey, &tmp))
62 result->value.reset(new std::string(tmp));
63 return result.Pass();
66 void ParseResponseCookieImpl(const base::DictionaryValue* dict,
67 helpers::ResponseCookie* cookie) {
68 std::string string_tmp;
69 int int_tmp = 0;
70 bool bool_tmp = false;
71 if (dict->GetString(keys::kNameKey, &string_tmp))
72 cookie->name.reset(new std::string(string_tmp));
73 if (dict->GetString(keys::kValueKey, &string_tmp))
74 cookie->value.reset(new std::string(string_tmp));
75 if (dict->GetString(keys::kExpiresKey, &string_tmp))
76 cookie->expires.reset(new std::string(string_tmp));
77 if (dict->GetInteger(keys::kMaxAgeKey, &int_tmp))
78 cookie->max_age.reset(new int(int_tmp));
79 if (dict->GetString(keys::kDomainKey, &string_tmp))
80 cookie->domain.reset(new std::string(string_tmp));
81 if (dict->GetString(keys::kPathKey, &string_tmp))
82 cookie->path.reset(new std::string(string_tmp));
83 if (dict->GetBoolean(keys::kSecureKey, &bool_tmp))
84 cookie->secure.reset(new bool(bool_tmp));
85 if (dict->GetBoolean(keys::kHttpOnlyKey, &bool_tmp))
86 cookie->http_only.reset(new bool(bool_tmp));
89 scoped_ptr<helpers::ResponseCookie> ParseResponseCookie(
90 const base::DictionaryValue* dict) {
91 scoped_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie);
92 ParseResponseCookieImpl(dict, result.get());
93 return result.Pass();
96 scoped_ptr<helpers::FilterResponseCookie> ParseFilterResponseCookie(
97 const base::DictionaryValue* dict) {
98 scoped_ptr<helpers::FilterResponseCookie> result(
99 new helpers::FilterResponseCookie);
100 ParseResponseCookieImpl(dict, result.get());
102 int int_tmp = 0;
103 bool bool_tmp = false;
104 if (dict->GetInteger(keys::kAgeUpperBoundKey, &int_tmp))
105 result->age_upper_bound.reset(new int(int_tmp));
106 if (dict->GetInteger(keys::kAgeLowerBoundKey, &int_tmp))
107 result->age_lower_bound.reset(new int(int_tmp));
108 if (dict->GetBoolean(keys::kSessionCookieKey, &bool_tmp))
109 result->session_cookie.reset(new bool(bool_tmp));
110 return result.Pass();
113 // Helper function for WebRequestActions that can be instantiated by just
114 // calling the constructor.
115 template <class T>
116 scoped_refptr<const WebRequestAction> CallConstructorFactoryMethod(
117 const std::string& instance_type,
118 const base::Value* value,
119 std::string* error,
120 bool* bad_message) {
121 return scoped_refptr<const WebRequestAction>(new T);
124 scoped_refptr<const WebRequestAction> CreateRedirectRequestAction(
125 const std::string& instance_type,
126 const base::Value* value,
127 std::string* error,
128 bool* bad_message) {
129 const base::DictionaryValue* dict = NULL;
130 CHECK(value->GetAsDictionary(&dict));
131 std::string redirect_url_string;
132 INPUT_FORMAT_VALIDATE(
133 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string));
134 GURL redirect_url(redirect_url_string);
135 return scoped_refptr<const WebRequestAction>(
136 new WebRequestRedirectAction(redirect_url));
139 scoped_refptr<const WebRequestAction> CreateRedirectRequestByRegExAction(
140 const std::string& instance_type,
141 const base::Value* value,
142 std::string* error,
143 bool* bad_message) {
144 const base::DictionaryValue* dict = NULL;
145 CHECK(value->GetAsDictionary(&dict));
146 std::string from;
147 std::string to;
148 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from));
149 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to));
151 to = WebRequestRedirectByRegExAction::PerlToRe2Style(to);
153 RE2::Options options;
154 options.set_case_sensitive(false);
155 scoped_ptr<RE2> from_pattern(new RE2(from, options));
157 if (!from_pattern->ok()) {
158 *error = "Invalid pattern '" + from + "' -> '" + to + "'";
159 return scoped_refptr<const WebRequestAction>(NULL);
161 return scoped_refptr<const WebRequestAction>(
162 new WebRequestRedirectByRegExAction(from_pattern.Pass(), to));
165 scoped_refptr<const WebRequestAction> CreateSetRequestHeaderAction(
166 const std::string& instance_type,
167 const base::Value* json_value,
168 std::string* error,
169 bool* bad_message) {
170 const base::DictionaryValue* dict = NULL;
171 CHECK(json_value->GetAsDictionary(&dict));
172 std::string name;
173 std::string value;
174 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
175 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
176 if (!net::HttpUtil::IsValidHeaderName(name)) {
177 *error = extension_web_request_api_constants::kInvalidHeaderName;
178 return scoped_refptr<const WebRequestAction>(NULL);
180 if (!net::HttpUtil::IsValidHeaderValue(value)) {
181 *error = ErrorUtils::FormatErrorMessage(
182 extension_web_request_api_constants::kInvalidHeaderValue, name);
183 return scoped_refptr<const WebRequestAction>(NULL);
185 return scoped_refptr<const WebRequestAction>(
186 new WebRequestSetRequestHeaderAction(name, value));
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>(NULL);
202 return scoped_refptr<const WebRequestAction>(
203 new WebRequestRemoveRequestHeaderAction(name));
206 scoped_refptr<const WebRequestAction> CreateAddResponseHeaderAction(
207 const std::string& instance_type,
208 const base::Value* json_value,
209 std::string* error,
210 bool* bad_message) {
211 const base::DictionaryValue* dict = NULL;
212 CHECK(json_value->GetAsDictionary(&dict));
213 std::string name;
214 std::string value;
215 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
216 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
217 if (!net::HttpUtil::IsValidHeaderName(name)) {
218 *error = extension_web_request_api_constants::kInvalidHeaderName;
219 return scoped_refptr<const WebRequestAction>(NULL);
221 if (!net::HttpUtil::IsValidHeaderValue(value)) {
222 *error = ErrorUtils::FormatErrorMessage(
223 extension_web_request_api_constants::kInvalidHeaderValue, name);
224 return scoped_refptr<const WebRequestAction>(NULL);
226 return scoped_refptr<const WebRequestAction>(
227 new WebRequestAddResponseHeaderAction(name, value));
230 scoped_refptr<const WebRequestAction> CreateRemoveResponseHeaderAction(
231 const std::string& instance_type,
232 const base::Value* json_value,
233 std::string* error,
234 bool* bad_message) {
235 const base::DictionaryValue* dict = NULL;
236 CHECK(json_value->GetAsDictionary(&dict));
237 std::string name;
238 std::string value;
239 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
240 bool has_value = dict->GetString(keys::kValueKey, &value);
241 if (!net::HttpUtil::IsValidHeaderName(name)) {
242 *error = extension_web_request_api_constants::kInvalidHeaderName;
243 return scoped_refptr<const WebRequestAction>(NULL);
245 if (has_value && !net::HttpUtil::IsValidHeaderValue(value)) {
246 *error = ErrorUtils::FormatErrorMessage(
247 extension_web_request_api_constants::kInvalidHeaderValue, name);
248 return scoped_refptr<const WebRequestAction>(NULL);
250 return scoped_refptr<const WebRequestAction>(
251 new WebRequestRemoveResponseHeaderAction(name, value, has_value));
254 scoped_refptr<const WebRequestAction> CreateIgnoreRulesAction(
255 const std::string& instance_type,
256 const base::Value* value,
257 std::string* error,
258 bool* bad_message) {
259 const base::DictionaryValue* dict = NULL;
260 CHECK(value->GetAsDictionary(&dict));
261 bool has_parameter = false;
262 int minimum_priority = std::numeric_limits<int>::min();
263 std::string ignore_tag;
264 if (dict->HasKey(keys::kLowerPriorityThanKey)) {
265 INPUT_FORMAT_VALIDATE(
266 dict->GetInteger(keys::kLowerPriorityThanKey, &minimum_priority));
267 has_parameter = true;
269 if (dict->HasKey(keys::kHasTagKey)) {
270 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kHasTagKey, &ignore_tag));
271 has_parameter = true;
273 if (!has_parameter) {
274 *error = kIgnoreRulesRequiresParameterError;
275 return scoped_refptr<const WebRequestAction>(NULL);
277 return scoped_refptr<const WebRequestAction>(
278 new WebRequestIgnoreRulesAction(minimum_priority, ignore_tag));
281 scoped_refptr<const WebRequestAction> CreateRequestCookieAction(
282 const std::string& instance_type,
283 const base::Value* value,
284 std::string* error,
285 bool* bad_message) {
286 using extension_web_request_api_helpers::RequestCookieModification;
288 const base::DictionaryValue* dict = NULL;
289 CHECK(value->GetAsDictionary(&dict));
291 linked_ptr<RequestCookieModification> modification(
292 new RequestCookieModification);
294 // Get modification type.
295 if (instance_type == keys::kAddRequestCookieType)
296 modification->type = helpers::ADD;
297 else if (instance_type == keys::kEditRequestCookieType)
298 modification->type = helpers::EDIT;
299 else if (instance_type == keys::kRemoveRequestCookieType)
300 modification->type = helpers::REMOVE;
301 else
302 INPUT_FORMAT_VALIDATE(false);
304 // Get filter.
305 if (modification->type == helpers::EDIT ||
306 modification->type == helpers::REMOVE) {
307 const base::DictionaryValue* filter = NULL;
308 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
309 modification->filter = ParseRequestCookie(filter);
312 // Get new value.
313 if (modification->type == helpers::ADD) {
314 const base::DictionaryValue* value = NULL;
315 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
316 modification->modification = ParseRequestCookie(value);
317 } else if (modification->type == helpers::EDIT) {
318 const base::DictionaryValue* value = NULL;
319 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
320 modification->modification = ParseRequestCookie(value);
323 return scoped_refptr<const WebRequestAction>(
324 new WebRequestRequestCookieAction(modification));
327 scoped_refptr<const WebRequestAction> CreateResponseCookieAction(
328 const std::string& instance_type,
329 const base::Value* value,
330 std::string* error,
331 bool* bad_message) {
332 using extension_web_request_api_helpers::ResponseCookieModification;
334 const base::DictionaryValue* dict = NULL;
335 CHECK(value->GetAsDictionary(&dict));
337 linked_ptr<ResponseCookieModification> modification(
338 new ResponseCookieModification);
340 // Get modification type.
341 if (instance_type == keys::kAddResponseCookieType)
342 modification->type = helpers::ADD;
343 else if (instance_type == keys::kEditResponseCookieType)
344 modification->type = helpers::EDIT;
345 else if (instance_type == keys::kRemoveResponseCookieType)
346 modification->type = helpers::REMOVE;
347 else
348 INPUT_FORMAT_VALIDATE(false);
350 // Get filter.
351 if (modification->type == helpers::EDIT ||
352 modification->type == helpers::REMOVE) {
353 const base::DictionaryValue* filter = NULL;
354 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
355 modification->filter = ParseFilterResponseCookie(filter);
358 // Get new value.
359 if (modification->type == helpers::ADD) {
360 const base::DictionaryValue* value = NULL;
361 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
362 modification->modification = ParseResponseCookie(value);
363 } else if (modification->type == helpers::EDIT) {
364 const base::DictionaryValue* value = NULL;
365 INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
366 modification->modification = ParseResponseCookie(value);
369 return scoped_refptr<const WebRequestAction>(
370 new WebRequestResponseCookieAction(modification));
373 scoped_refptr<const WebRequestAction> CreateSendMessageToExtensionAction(
374 const std::string& name,
375 const base::Value* value,
376 std::string* error,
377 bool* bad_message) {
378 const base::DictionaryValue* dict = NULL;
379 CHECK(value->GetAsDictionary(&dict));
380 std::string message;
381 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kMessageKey, &message));
382 return scoped_refptr<const WebRequestAction>(
383 new WebRequestSendMessageToExtensionAction(message));
386 struct WebRequestActionFactory {
387 DedupingFactory<WebRequestAction> factory;
389 WebRequestActionFactory() : factory(5) {
390 factory.RegisterFactoryMethod(
391 keys::kAddRequestCookieType,
392 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
393 &CreateRequestCookieAction);
394 factory.RegisterFactoryMethod(
395 keys::kAddResponseCookieType,
396 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
397 &CreateResponseCookieAction);
398 factory.RegisterFactoryMethod(
399 keys::kAddResponseHeaderType,
400 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
401 &CreateAddResponseHeaderAction);
402 factory.RegisterFactoryMethod(
403 keys::kCancelRequestType,
404 DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
405 &CallConstructorFactoryMethod<WebRequestCancelAction>);
406 factory.RegisterFactoryMethod(
407 keys::kEditRequestCookieType,
408 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
409 &CreateRequestCookieAction);
410 factory.RegisterFactoryMethod(
411 keys::kEditResponseCookieType,
412 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
413 &CreateResponseCookieAction);
414 factory.RegisterFactoryMethod(
415 keys::kRedirectByRegExType,
416 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
417 &CreateRedirectRequestByRegExAction);
418 factory.RegisterFactoryMethod(
419 keys::kRedirectRequestType,
420 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
421 &CreateRedirectRequestAction);
422 factory.RegisterFactoryMethod(
423 keys::kRedirectToTransparentImageType,
424 DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
425 &CallConstructorFactoryMethod<
426 WebRequestRedirectToTransparentImageAction>);
427 factory.RegisterFactoryMethod(
428 keys::kRedirectToEmptyDocumentType,
429 DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED,
430 &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>);
431 factory.RegisterFactoryMethod(
432 keys::kRemoveRequestCookieType,
433 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
434 &CreateRequestCookieAction);
435 factory.RegisterFactoryMethod(
436 keys::kRemoveResponseCookieType,
437 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
438 &CreateResponseCookieAction);
439 factory.RegisterFactoryMethod(
440 keys::kSetRequestHeaderType,
441 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
442 &CreateSetRequestHeaderAction);
443 factory.RegisterFactoryMethod(
444 keys::kRemoveRequestHeaderType,
445 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
446 &CreateRemoveRequestHeaderAction);
447 factory.RegisterFactoryMethod(
448 keys::kRemoveResponseHeaderType,
449 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
450 &CreateRemoveResponseHeaderAction);
451 factory.RegisterFactoryMethod(
452 keys::kIgnoreRulesType,
453 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
454 &CreateIgnoreRulesAction);
455 factory.RegisterFactoryMethod(
456 keys::kSendMessageToExtensionType,
457 DedupingFactory<WebRequestAction>::IS_PARAMETERIZED,
458 &CreateSendMessageToExtensionAction);
462 base::LazyInstance<WebRequestActionFactory>::Leaky
463 g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER;
465 } // namespace
468 // WebRequestAction
471 WebRequestAction::~WebRequestAction() {}
473 bool WebRequestAction::Equals(const WebRequestAction* other) const {
474 return type() == other->type();
477 bool WebRequestAction::HasPermission(const InfoMap* extension_info_map,
478 const std::string& extension_id,
479 const net::URLRequest* request,
480 bool crosses_incognito) const {
481 if (WebRequestPermissions::HideRequest(extension_info_map, request))
482 return false;
484 // In unit tests we don't have an extension_info_map object here and skip host
485 // permission checks.
486 if (!extension_info_map)
487 return true;
489 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
490 int process_id = info ? info->GetChildID() : 0;
492 // The embedder can always access all hosts from within a <webview>.
493 // The same is not true of extensions.
494 if (WebViewRendererState::GetInstance()->IsGuest(process_id))
495 return true;
497 WebRequestPermissions::HostPermissionsCheck permission_check =
498 WebRequestPermissions::REQUIRE_ALL_URLS;
499 switch (host_permissions_strategy()) {
500 case STRATEGY_DEFAULT: // Default value is already set.
501 break;
502 case STRATEGY_NONE:
503 permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST;
504 break;
505 case STRATEGY_HOST:
506 permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION;
507 break;
509 return WebRequestPermissions::CanExtensionAccessURL(
510 extension_info_map, extension_id, request->url(), crosses_incognito,
511 permission_check);
514 // static
515 scoped_refptr<const WebRequestAction> WebRequestAction::Create(
516 content::BrowserContext* browser_context,
517 const HostID& host_id,
518 const Extension* extension,
519 const base::Value& json_action,
520 std::string* error,
521 bool* bad_message) {
522 *error = "";
523 *bad_message = false;
525 const base::DictionaryValue* action_dict = NULL;
526 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
528 std::string instance_type;
529 INPUT_FORMAT_VALIDATE(
530 action_dict->GetString(keys::kInstanceTypeKey, &instance_type));
532 WebRequestActionFactory& factory = g_web_request_action_factory.Get();
533 return factory.factory.Instantiate(
534 instance_type, action_dict, error, bad_message);
537 void WebRequestAction::Apply(const std::string& extension_id,
538 base::Time extension_install_time,
539 ApplyInfo* apply_info) const {
540 if (!HasPermission(apply_info->extension_info_map, extension_id,
541 apply_info->request_data.request,
542 apply_info->crosses_incognito))
543 return;
544 if (stages() & apply_info->request_data.stage) {
545 LinkedPtrEventResponseDelta delta = CreateDelta(
546 apply_info->request_data, extension_id, extension_install_time);
547 if (delta.get())
548 apply_info->deltas->push_back(delta);
549 if (type() == WebRequestAction::ACTION_IGNORE_RULES) {
550 const WebRequestIgnoreRulesAction* ignore_action =
551 static_cast<const WebRequestIgnoreRulesAction*>(this);
552 if (!ignore_action->ignore_tag().empty())
553 apply_info->ignored_tags->insert(ignore_action->ignore_tag());
558 WebRequestAction::WebRequestAction(int stages,
559 Type type,
560 int minimum_priority,
561 HostPermissionsStrategy strategy)
562 : stages_(stages),
563 type_(type),
564 minimum_priority_(minimum_priority),
565 host_permissions_strategy_(strategy) {}
568 // WebRequestCancelAction
571 WebRequestCancelAction::WebRequestCancelAction()
572 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
573 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
574 ACTION_CANCEL_REQUEST,
575 std::numeric_limits<int>::min(),
576 STRATEGY_NONE) {}
578 WebRequestCancelAction::~WebRequestCancelAction() {}
580 std::string WebRequestCancelAction::GetName() const {
581 return keys::kCancelRequestType;
584 LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta(
585 const WebRequestData& request_data,
586 const std::string& extension_id,
587 const base::Time& extension_install_time) const {
588 CHECK(request_data.stage & stages());
589 LinkedPtrEventResponseDelta result(
590 new helpers::EventResponseDelta(extension_id, extension_install_time));
591 result->cancel = true;
592 return result;
596 // WebRequestRedirectAction
599 WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url)
600 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
601 ACTION_REDIRECT_REQUEST,
602 std::numeric_limits<int>::min(),
603 STRATEGY_DEFAULT),
604 redirect_url_(redirect_url) {}
606 WebRequestRedirectAction::~WebRequestRedirectAction() {}
608 bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const {
609 return WebRequestAction::Equals(other) &&
610 redirect_url_ ==
611 static_cast<const WebRequestRedirectAction*>(other)->redirect_url_;
614 std::string WebRequestRedirectAction::GetName() const {
615 return keys::kRedirectRequestType;
618 LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta(
619 const WebRequestData& request_data,
620 const std::string& extension_id,
621 const base::Time& extension_install_time) const {
622 CHECK(request_data.stage & stages());
623 if (request_data.request->url() == redirect_url_)
624 return LinkedPtrEventResponseDelta(NULL);
625 LinkedPtrEventResponseDelta result(
626 new helpers::EventResponseDelta(extension_id, extension_install_time));
627 result->new_url = redirect_url_;
628 return result;
632 // WebRequestRedirectToTransparentImageAction
635 WebRequestRedirectToTransparentImageAction::
636 WebRequestRedirectToTransparentImageAction()
637 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
638 ACTION_REDIRECT_TO_TRANSPARENT_IMAGE,
639 std::numeric_limits<int>::min(),
640 STRATEGY_NONE) {}
642 WebRequestRedirectToTransparentImageAction::
643 ~WebRequestRedirectToTransparentImageAction() {}
645 std::string WebRequestRedirectToTransparentImageAction::GetName() const {
646 return keys::kRedirectToTransparentImageType;
649 LinkedPtrEventResponseDelta
650 WebRequestRedirectToTransparentImageAction::CreateDelta(
651 const WebRequestData& request_data,
652 const std::string& extension_id,
653 const base::Time& extension_install_time) const {
654 CHECK(request_data.stage & stages());
655 LinkedPtrEventResponseDelta result(
656 new helpers::EventResponseDelta(extension_id, extension_install_time));
657 result->new_url = GURL(kTransparentImageUrl);
658 return result;
662 // WebRequestRedirectToEmptyDocumentAction
665 WebRequestRedirectToEmptyDocumentAction::
666 WebRequestRedirectToEmptyDocumentAction()
667 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
668 ACTION_REDIRECT_TO_EMPTY_DOCUMENT,
669 std::numeric_limits<int>::min(),
670 STRATEGY_NONE) {}
672 WebRequestRedirectToEmptyDocumentAction::
673 ~WebRequestRedirectToEmptyDocumentAction() {}
675 std::string WebRequestRedirectToEmptyDocumentAction::GetName() const {
676 return keys::kRedirectToEmptyDocumentType;
679 LinkedPtrEventResponseDelta
680 WebRequestRedirectToEmptyDocumentAction::CreateDelta(
681 const WebRequestData& request_data,
682 const std::string& extension_id,
683 const base::Time& extension_install_time) const {
684 CHECK(request_data.stage & stages());
685 LinkedPtrEventResponseDelta result(
686 new helpers::EventResponseDelta(extension_id, extension_install_time));
687 result->new_url = GURL(kEmptyDocumentUrl);
688 return result;
692 // WebRequestRedirectByRegExAction
695 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction(
696 scoped_ptr<RE2> from_pattern,
697 const std::string& to_pattern)
698 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
699 ACTION_REDIRECT_BY_REGEX_DOCUMENT,
700 std::numeric_limits<int>::min(),
701 STRATEGY_DEFAULT),
702 from_pattern_(from_pattern.Pass()),
703 to_pattern_(to_pattern.data(), to_pattern.size()) {}
705 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
707 // About the syntax of the two languages:
709 // ICU (Perl) states:
710 // $n The text of capture group n will be substituted for $n. n must be >= 0
711 // and not greater than the number of capture groups. A $ not followed by a
712 // digit has no special meaning, and will appear in the substitution text
713 // as itself, a $.
714 // \ Treat the following character as a literal, suppressing any special
715 // meaning. Backslash escaping in substitution text is only required for
716 // '$' and '\', but may be used on any other character without bad effects.
718 // RE2, derived from RE2::Rewrite()
719 // \ May only be followed by a digit or another \. If followed by a single
720 // digit, both characters represent the respective capture group. If followed
721 // by another \, it is used as an escape sequence.
723 // static
724 std::string WebRequestRedirectByRegExAction::PerlToRe2Style(
725 const std::string& perl) {
726 std::string::const_iterator i = perl.begin();
727 std::string result;
728 while (i != perl.end()) {
729 if (*i == '$') {
730 ++i;
731 if (i == perl.end()) {
732 result += '$';
733 return result;
734 } else if (isdigit(*i)) {
735 result += '\\';
736 result += *i;
737 } else {
738 result += '$';
739 result += *i;
741 } else if (*i == '\\') {
742 ++i;
743 if (i == perl.end()) {
744 result += '\\';
745 } else if (*i == '$') {
746 result += '$';
747 } else if (*i == '\\') {
748 result += "\\\\";
749 } else {
750 result += *i;
752 } else {
753 result += *i;
755 ++i;
757 return result;
760 bool WebRequestRedirectByRegExAction::Equals(
761 const WebRequestAction* other) const {
762 if (!WebRequestAction::Equals(other))
763 return false;
764 const WebRequestRedirectByRegExAction* casted_other =
765 static_cast<const WebRequestRedirectByRegExAction*>(other);
766 return from_pattern_->pattern() == casted_other->from_pattern_->pattern() &&
767 to_pattern_ == casted_other->to_pattern_;
770 std::string WebRequestRedirectByRegExAction::GetName() const {
771 return keys::kRedirectByRegExType;
774 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta(
775 const WebRequestData& request_data,
776 const std::string& extension_id,
777 const base::Time& extension_install_time) const {
778 CHECK(request_data.stage & stages());
779 CHECK(from_pattern_.get());
781 const std::string& old_url = request_data.request->url().spec();
782 std::string new_url = old_url;
783 if (!RE2::Replace(&new_url, *from_pattern_, to_pattern_) ||
784 new_url == old_url) {
785 return LinkedPtrEventResponseDelta(NULL);
788 LinkedPtrEventResponseDelta result(
789 new extension_web_request_api_helpers::EventResponseDelta(
790 extension_id, extension_install_time));
791 result->new_url = GURL(new_url);
792 return result;
796 // WebRequestSetRequestHeaderAction
799 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction(
800 const std::string& name,
801 const std::string& value)
802 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
803 ACTION_SET_REQUEST_HEADER,
804 std::numeric_limits<int>::min(),
805 STRATEGY_DEFAULT),
806 name_(name),
807 value_(value) {}
809 WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {}
811 bool WebRequestSetRequestHeaderAction::Equals(
812 const WebRequestAction* other) const {
813 if (!WebRequestAction::Equals(other))
814 return false;
815 const WebRequestSetRequestHeaderAction* casted_other =
816 static_cast<const WebRequestSetRequestHeaderAction*>(other);
817 return name_ == casted_other->name_ && value_ == casted_other->value_;
820 std::string WebRequestSetRequestHeaderAction::GetName() const {
821 return keys::kSetRequestHeaderType;
825 LinkedPtrEventResponseDelta
826 WebRequestSetRequestHeaderAction::CreateDelta(
827 const WebRequestData& request_data,
828 const std::string& extension_id,
829 const base::Time& extension_install_time) const {
830 CHECK(request_data.stage & stages());
831 LinkedPtrEventResponseDelta result(
832 new helpers::EventResponseDelta(extension_id, extension_install_time));
833 result->modified_request_headers.SetHeader(name_, value_);
834 return result;
838 // WebRequestRemoveRequestHeaderAction
841 WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction(
842 const std::string& name)
843 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
844 ACTION_REMOVE_REQUEST_HEADER,
845 std::numeric_limits<int>::min(),
846 STRATEGY_DEFAULT),
847 name_(name) {}
849 WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {}
851 bool WebRequestRemoveRequestHeaderAction::Equals(
852 const WebRequestAction* other) const {
853 if (!WebRequestAction::Equals(other))
854 return false;
855 const WebRequestRemoveRequestHeaderAction* casted_other =
856 static_cast<const WebRequestRemoveRequestHeaderAction*>(other);
857 return name_ == casted_other->name_;
860 std::string WebRequestRemoveRequestHeaderAction::GetName() const {
861 return keys::kRemoveRequestHeaderType;
864 LinkedPtrEventResponseDelta
865 WebRequestRemoveRequestHeaderAction::CreateDelta(
866 const WebRequestData& request_data,
867 const std::string& extension_id,
868 const base::Time& extension_install_time) const {
869 CHECK(request_data.stage & stages());
870 LinkedPtrEventResponseDelta result(
871 new helpers::EventResponseDelta(extension_id, extension_install_time));
872 result->deleted_request_headers.push_back(name_);
873 return result;
877 // WebRequestAddResponseHeaderAction
880 WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction(
881 const std::string& name,
882 const std::string& value)
883 : WebRequestAction(ON_HEADERS_RECEIVED,
884 ACTION_ADD_RESPONSE_HEADER,
885 std::numeric_limits<int>::min(),
886 STRATEGY_DEFAULT),
887 name_(name),
888 value_(value) {}
890 WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {}
892 bool WebRequestAddResponseHeaderAction::Equals(
893 const WebRequestAction* other) const {
894 if (!WebRequestAction::Equals(other))
895 return false;
896 const WebRequestAddResponseHeaderAction* casted_other =
897 static_cast<const WebRequestAddResponseHeaderAction*>(other);
898 return name_ == casted_other->name_ && value_ == casted_other->value_;
901 std::string WebRequestAddResponseHeaderAction::GetName() const {
902 return keys::kAddResponseHeaderType;
905 LinkedPtrEventResponseDelta
906 WebRequestAddResponseHeaderAction::CreateDelta(
907 const WebRequestData& request_data,
908 const std::string& extension_id,
909 const base::Time& extension_install_time) const {
910 CHECK(request_data.stage & stages());
911 const net::HttpResponseHeaders* headers =
912 request_data.original_response_headers;
913 if (!headers)
914 return LinkedPtrEventResponseDelta(NULL);
916 // Don't generate the header if it exists already.
917 if (headers->HasHeaderValue(name_, value_))
918 return LinkedPtrEventResponseDelta(NULL);
920 LinkedPtrEventResponseDelta result(
921 new helpers::EventResponseDelta(extension_id, extension_install_time));
922 result->added_response_headers.push_back(make_pair(name_, value_));
923 return result;
927 // WebRequestRemoveResponseHeaderAction
930 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction(
931 const std::string& name,
932 const std::string& value,
933 bool has_value)
934 : WebRequestAction(ON_HEADERS_RECEIVED,
935 ACTION_REMOVE_RESPONSE_HEADER,
936 std::numeric_limits<int>::min(),
937 STRATEGY_DEFAULT),
938 name_(name),
939 value_(value),
940 has_value_(has_value) {}
942 WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {}
944 bool WebRequestRemoveResponseHeaderAction::Equals(
945 const WebRequestAction* other) const {
946 if (!WebRequestAction::Equals(other))
947 return false;
948 const WebRequestRemoveResponseHeaderAction* casted_other =
949 static_cast<const WebRequestRemoveResponseHeaderAction*>(other);
950 return name_ == casted_other->name_ && value_ == casted_other->value_ &&
951 has_value_ == casted_other->has_value_;
954 std::string WebRequestRemoveResponseHeaderAction::GetName() const {
955 return keys::kRemoveResponseHeaderType;
958 LinkedPtrEventResponseDelta
959 WebRequestRemoveResponseHeaderAction::CreateDelta(
960 const WebRequestData& request_data,
961 const std::string& extension_id,
962 const base::Time& extension_install_time) const {
963 CHECK(request_data.stage & stages());
964 const net::HttpResponseHeaders* headers =
965 request_data.original_response_headers;
966 if (!headers)
967 return LinkedPtrEventResponseDelta(NULL);
969 LinkedPtrEventResponseDelta result(
970 new helpers::EventResponseDelta(extension_id, extension_install_time));
971 void* iter = NULL;
972 std::string current_value;
973 while (headers->EnumerateHeader(&iter, name_, &current_value)) {
974 if (has_value_ &&
975 (current_value.size() != value_.size() ||
976 !std::equal(current_value.begin(), current_value.end(),
977 value_.begin(),
978 base::CaseInsensitiveCompare<char>()))) {
979 continue;
981 result->deleted_response_headers.push_back(make_pair(name_, current_value));
983 return result;
987 // WebRequestIgnoreRulesAction
990 WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction(
991 int minimum_priority,
992 const std::string& ignore_tag)
993 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
994 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
995 ACTION_IGNORE_RULES,
996 minimum_priority,
997 STRATEGY_NONE),
998 ignore_tag_(ignore_tag) {}
1000 WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {}
1002 bool WebRequestIgnoreRulesAction::Equals(const WebRequestAction* other) const {
1003 if (!WebRequestAction::Equals(other))
1004 return false;
1005 const WebRequestIgnoreRulesAction* casted_other =
1006 static_cast<const WebRequestIgnoreRulesAction*>(other);
1007 return minimum_priority() == casted_other->minimum_priority() &&
1008 ignore_tag_ == casted_other->ignore_tag_;
1011 std::string WebRequestIgnoreRulesAction::GetName() const {
1012 return keys::kIgnoreRulesType;
1015 LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta(
1016 const WebRequestData& request_data,
1017 const std::string& extension_id,
1018 const base::Time& extension_install_time) const {
1019 CHECK(request_data.stage & stages());
1020 return LinkedPtrEventResponseDelta(NULL);
1024 // WebRequestRequestCookieAction
1027 WebRequestRequestCookieAction::WebRequestRequestCookieAction(
1028 linked_ptr<RequestCookieModification> request_cookie_modification)
1029 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
1030 ACTION_MODIFY_REQUEST_COOKIE,
1031 std::numeric_limits<int>::min(),
1032 STRATEGY_DEFAULT),
1033 request_cookie_modification_(request_cookie_modification) {
1034 CHECK(request_cookie_modification_.get());
1037 WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
1039 bool WebRequestRequestCookieAction::Equals(
1040 const WebRequestAction* other) const {
1041 if (!WebRequestAction::Equals(other))
1042 return false;
1043 const WebRequestRequestCookieAction* casted_other =
1044 static_cast<const WebRequestRequestCookieAction*>(other);
1045 return helpers::NullableEquals(
1046 request_cookie_modification_.get(),
1047 casted_other->request_cookie_modification_.get());
1050 std::string WebRequestRequestCookieAction::GetName() const {
1051 switch (request_cookie_modification_->type) {
1052 case helpers::ADD:
1053 return keys::kAddRequestCookieType;
1054 case helpers::EDIT:
1055 return keys::kEditRequestCookieType;
1056 case helpers::REMOVE:
1057 return keys::kRemoveRequestCookieType;
1059 NOTREACHED();
1060 return "";
1063 LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta(
1064 const WebRequestData& request_data,
1065 const std::string& extension_id,
1066 const base::Time& extension_install_time) const {
1067 CHECK(request_data.stage & stages());
1068 LinkedPtrEventResponseDelta result(
1069 new extension_web_request_api_helpers::EventResponseDelta(
1070 extension_id, extension_install_time));
1071 result->request_cookie_modifications.push_back(
1072 request_cookie_modification_);
1073 return result;
1077 // WebRequestResponseCookieAction
1080 WebRequestResponseCookieAction::WebRequestResponseCookieAction(
1081 linked_ptr<ResponseCookieModification> response_cookie_modification)
1082 : WebRequestAction(ON_HEADERS_RECEIVED,
1083 ACTION_MODIFY_RESPONSE_COOKIE,
1084 std::numeric_limits<int>::min(),
1085 STRATEGY_DEFAULT),
1086 response_cookie_modification_(response_cookie_modification) {
1087 CHECK(response_cookie_modification_.get());
1090 WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
1092 bool WebRequestResponseCookieAction::Equals(
1093 const WebRequestAction* other) const {
1094 if (!WebRequestAction::Equals(other))
1095 return false;
1096 const WebRequestResponseCookieAction* casted_other =
1097 static_cast<const WebRequestResponseCookieAction*>(other);
1098 return helpers::NullableEquals(
1099 response_cookie_modification_.get(),
1100 casted_other->response_cookie_modification_.get());
1103 std::string WebRequestResponseCookieAction::GetName() const {
1104 switch (response_cookie_modification_->type) {
1105 case helpers::ADD:
1106 return keys::kAddResponseCookieType;
1107 case helpers::EDIT:
1108 return keys::kEditResponseCookieType;
1109 case helpers::REMOVE:
1110 return keys::kRemoveResponseCookieType;
1112 NOTREACHED();
1113 return "";
1116 LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta(
1117 const WebRequestData& request_data,
1118 const std::string& extension_id,
1119 const base::Time& extension_install_time) const {
1120 CHECK(request_data.stage & stages());
1121 LinkedPtrEventResponseDelta result(
1122 new extension_web_request_api_helpers::EventResponseDelta(
1123 extension_id, extension_install_time));
1124 result->response_cookie_modifications.push_back(
1125 response_cookie_modification_);
1126 return result;
1130 // WebRequestSendMessageToExtensionAction
1133 WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction(
1134 const std::string& message)
1135 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
1136 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
1137 ACTION_SEND_MESSAGE_TO_EXTENSION,
1138 std::numeric_limits<int>::min(),
1139 STRATEGY_HOST),
1140 message_(message) {}
1142 WebRequestSendMessageToExtensionAction::
1143 ~WebRequestSendMessageToExtensionAction() {}
1145 bool WebRequestSendMessageToExtensionAction::Equals(
1146 const WebRequestAction* other) const {
1147 if (!WebRequestAction::Equals(other))
1148 return false;
1149 const WebRequestSendMessageToExtensionAction* casted_other =
1150 static_cast<const WebRequestSendMessageToExtensionAction*>(other);
1151 return message_ == casted_other->message_;
1154 std::string WebRequestSendMessageToExtensionAction::GetName() const {
1155 return keys::kSendMessageToExtensionType;
1158 LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta(
1159 const WebRequestData& request_data,
1160 const std::string& extension_id,
1161 const base::Time& extension_install_time) const {
1162 CHECK(request_data.stage & stages());
1163 LinkedPtrEventResponseDelta result(
1164 new extension_web_request_api_helpers::EventResponseDelta(
1165 extension_id, extension_install_time));
1166 result->messages_to_extension.insert(message_);
1167 return result;
1170 } // namespace extensions