Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / declarative_webrequest / webrequest_action.cc
blob1a777cef2d8e6593931b50ac07deacc3d92c1a96
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 Extension* extension,
518 const base::Value& json_action,
519 std::string* error,
520 bool* bad_message) {
521 *error = "";
522 *bad_message = false;
524 const base::DictionaryValue* action_dict = NULL;
525 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
527 std::string instance_type;
528 INPUT_FORMAT_VALIDATE(
529 action_dict->GetString(keys::kInstanceTypeKey, &instance_type));
531 WebRequestActionFactory& factory = g_web_request_action_factory.Get();
532 return factory.factory.Instantiate(
533 instance_type, action_dict, error, bad_message);
536 void WebRequestAction::Apply(const std::string& extension_id,
537 base::Time extension_install_time,
538 ApplyInfo* apply_info) const {
539 if (!HasPermission(apply_info->extension_info_map, extension_id,
540 apply_info->request_data.request,
541 apply_info->crosses_incognito))
542 return;
543 if (stages() & apply_info->request_data.stage) {
544 LinkedPtrEventResponseDelta delta = CreateDelta(
545 apply_info->request_data, extension_id, extension_install_time);
546 if (delta.get())
547 apply_info->deltas->push_back(delta);
548 if (type() == WebRequestAction::ACTION_IGNORE_RULES) {
549 const WebRequestIgnoreRulesAction* ignore_action =
550 static_cast<const WebRequestIgnoreRulesAction*>(this);
551 if (!ignore_action->ignore_tag().empty())
552 apply_info->ignored_tags->insert(ignore_action->ignore_tag());
557 WebRequestAction::WebRequestAction(int stages,
558 Type type,
559 int minimum_priority,
560 HostPermissionsStrategy strategy)
561 : stages_(stages),
562 type_(type),
563 minimum_priority_(minimum_priority),
564 host_permissions_strategy_(strategy) {}
567 // WebRequestCancelAction
570 WebRequestCancelAction::WebRequestCancelAction()
571 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
572 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
573 ACTION_CANCEL_REQUEST,
574 std::numeric_limits<int>::min(),
575 STRATEGY_NONE) {}
577 WebRequestCancelAction::~WebRequestCancelAction() {}
579 std::string WebRequestCancelAction::GetName() const {
580 return keys::kCancelRequestType;
583 LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta(
584 const WebRequestData& request_data,
585 const std::string& extension_id,
586 const base::Time& extension_install_time) const {
587 CHECK(request_data.stage & stages());
588 LinkedPtrEventResponseDelta result(
589 new helpers::EventResponseDelta(extension_id, extension_install_time));
590 result->cancel = true;
591 return result;
595 // WebRequestRedirectAction
598 WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url)
599 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
600 ACTION_REDIRECT_REQUEST,
601 std::numeric_limits<int>::min(),
602 STRATEGY_DEFAULT),
603 redirect_url_(redirect_url) {}
605 WebRequestRedirectAction::~WebRequestRedirectAction() {}
607 bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const {
608 return WebRequestAction::Equals(other) &&
609 redirect_url_ ==
610 static_cast<const WebRequestRedirectAction*>(other)->redirect_url_;
613 std::string WebRequestRedirectAction::GetName() const {
614 return keys::kRedirectRequestType;
617 LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta(
618 const WebRequestData& request_data,
619 const std::string& extension_id,
620 const base::Time& extension_install_time) const {
621 CHECK(request_data.stage & stages());
622 if (request_data.request->url() == redirect_url_)
623 return LinkedPtrEventResponseDelta(NULL);
624 LinkedPtrEventResponseDelta result(
625 new helpers::EventResponseDelta(extension_id, extension_install_time));
626 result->new_url = redirect_url_;
627 return result;
631 // WebRequestRedirectToTransparentImageAction
634 WebRequestRedirectToTransparentImageAction::
635 WebRequestRedirectToTransparentImageAction()
636 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
637 ACTION_REDIRECT_TO_TRANSPARENT_IMAGE,
638 std::numeric_limits<int>::min(),
639 STRATEGY_NONE) {}
641 WebRequestRedirectToTransparentImageAction::
642 ~WebRequestRedirectToTransparentImageAction() {}
644 std::string WebRequestRedirectToTransparentImageAction::GetName() const {
645 return keys::kRedirectToTransparentImageType;
648 LinkedPtrEventResponseDelta
649 WebRequestRedirectToTransparentImageAction::CreateDelta(
650 const WebRequestData& request_data,
651 const std::string& extension_id,
652 const base::Time& extension_install_time) const {
653 CHECK(request_data.stage & stages());
654 LinkedPtrEventResponseDelta result(
655 new helpers::EventResponseDelta(extension_id, extension_install_time));
656 result->new_url = GURL(kTransparentImageUrl);
657 return result;
661 // WebRequestRedirectToEmptyDocumentAction
664 WebRequestRedirectToEmptyDocumentAction::
665 WebRequestRedirectToEmptyDocumentAction()
666 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
667 ACTION_REDIRECT_TO_EMPTY_DOCUMENT,
668 std::numeric_limits<int>::min(),
669 STRATEGY_NONE) {}
671 WebRequestRedirectToEmptyDocumentAction::
672 ~WebRequestRedirectToEmptyDocumentAction() {}
674 std::string WebRequestRedirectToEmptyDocumentAction::GetName() const {
675 return keys::kRedirectToEmptyDocumentType;
678 LinkedPtrEventResponseDelta
679 WebRequestRedirectToEmptyDocumentAction::CreateDelta(
680 const WebRequestData& request_data,
681 const std::string& extension_id,
682 const base::Time& extension_install_time) const {
683 CHECK(request_data.stage & stages());
684 LinkedPtrEventResponseDelta result(
685 new helpers::EventResponseDelta(extension_id, extension_install_time));
686 result->new_url = GURL(kEmptyDocumentUrl);
687 return result;
691 // WebRequestRedirectByRegExAction
694 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction(
695 scoped_ptr<RE2> from_pattern,
696 const std::string& to_pattern)
697 : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED,
698 ACTION_REDIRECT_BY_REGEX_DOCUMENT,
699 std::numeric_limits<int>::min(),
700 STRATEGY_DEFAULT),
701 from_pattern_(from_pattern.Pass()),
702 to_pattern_(to_pattern.data(), to_pattern.size()) {}
704 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
706 // About the syntax of the two languages:
708 // ICU (Perl) states:
709 // $n The text of capture group n will be substituted for $n. n must be >= 0
710 // and not greater than the number of capture groups. A $ not followed by a
711 // digit has no special meaning, and will appear in the substitution text
712 // as itself, a $.
713 // \ Treat the following character as a literal, suppressing any special
714 // meaning. Backslash escaping in substitution text is only required for
715 // '$' and '\', but may be used on any other character without bad effects.
717 // RE2, derived from RE2::Rewrite()
718 // \ May only be followed by a digit or another \. If followed by a single
719 // digit, both characters represent the respective capture group. If followed
720 // by another \, it is used as an escape sequence.
722 // static
723 std::string WebRequestRedirectByRegExAction::PerlToRe2Style(
724 const std::string& perl) {
725 std::string::const_iterator i = perl.begin();
726 std::string result;
727 while (i != perl.end()) {
728 if (*i == '$') {
729 ++i;
730 if (i == perl.end()) {
731 result += '$';
732 return result;
733 } else if (isdigit(*i)) {
734 result += '\\';
735 result += *i;
736 } else {
737 result += '$';
738 result += *i;
740 } else if (*i == '\\') {
741 ++i;
742 if (i == perl.end()) {
743 result += '\\';
744 } else if (*i == '$') {
745 result += '$';
746 } else if (*i == '\\') {
747 result += "\\\\";
748 } else {
749 result += *i;
751 } else {
752 result += *i;
754 ++i;
756 return result;
759 bool WebRequestRedirectByRegExAction::Equals(
760 const WebRequestAction* other) const {
761 if (!WebRequestAction::Equals(other))
762 return false;
763 const WebRequestRedirectByRegExAction* casted_other =
764 static_cast<const WebRequestRedirectByRegExAction*>(other);
765 return from_pattern_->pattern() == casted_other->from_pattern_->pattern() &&
766 to_pattern_ == casted_other->to_pattern_;
769 std::string WebRequestRedirectByRegExAction::GetName() const {
770 return keys::kRedirectByRegExType;
773 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta(
774 const WebRequestData& request_data,
775 const std::string& extension_id,
776 const base::Time& extension_install_time) const {
777 CHECK(request_data.stage & stages());
778 CHECK(from_pattern_.get());
780 const std::string& old_url = request_data.request->url().spec();
781 std::string new_url = old_url;
782 if (!RE2::Replace(&new_url, *from_pattern_, to_pattern_) ||
783 new_url == old_url) {
784 return LinkedPtrEventResponseDelta(NULL);
787 LinkedPtrEventResponseDelta result(
788 new extension_web_request_api_helpers::EventResponseDelta(
789 extension_id, extension_install_time));
790 result->new_url = GURL(new_url);
791 return result;
795 // WebRequestSetRequestHeaderAction
798 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction(
799 const std::string& name,
800 const std::string& value)
801 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
802 ACTION_SET_REQUEST_HEADER,
803 std::numeric_limits<int>::min(),
804 STRATEGY_DEFAULT),
805 name_(name),
806 value_(value) {}
808 WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {}
810 bool WebRequestSetRequestHeaderAction::Equals(
811 const WebRequestAction* other) const {
812 if (!WebRequestAction::Equals(other))
813 return false;
814 const WebRequestSetRequestHeaderAction* casted_other =
815 static_cast<const WebRequestSetRequestHeaderAction*>(other);
816 return name_ == casted_other->name_ && value_ == casted_other->value_;
819 std::string WebRequestSetRequestHeaderAction::GetName() const {
820 return keys::kSetRequestHeaderType;
824 LinkedPtrEventResponseDelta
825 WebRequestSetRequestHeaderAction::CreateDelta(
826 const WebRequestData& request_data,
827 const std::string& extension_id,
828 const base::Time& extension_install_time) const {
829 CHECK(request_data.stage & stages());
830 LinkedPtrEventResponseDelta result(
831 new helpers::EventResponseDelta(extension_id, extension_install_time));
832 result->modified_request_headers.SetHeader(name_, value_);
833 return result;
837 // WebRequestRemoveRequestHeaderAction
840 WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction(
841 const std::string& name)
842 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
843 ACTION_REMOVE_REQUEST_HEADER,
844 std::numeric_limits<int>::min(),
845 STRATEGY_DEFAULT),
846 name_(name) {}
848 WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {}
850 bool WebRequestRemoveRequestHeaderAction::Equals(
851 const WebRequestAction* other) const {
852 if (!WebRequestAction::Equals(other))
853 return false;
854 const WebRequestRemoveRequestHeaderAction* casted_other =
855 static_cast<const WebRequestRemoveRequestHeaderAction*>(other);
856 return name_ == casted_other->name_;
859 std::string WebRequestRemoveRequestHeaderAction::GetName() const {
860 return keys::kRemoveRequestHeaderType;
863 LinkedPtrEventResponseDelta
864 WebRequestRemoveRequestHeaderAction::CreateDelta(
865 const WebRequestData& request_data,
866 const std::string& extension_id,
867 const base::Time& extension_install_time) const {
868 CHECK(request_data.stage & stages());
869 LinkedPtrEventResponseDelta result(
870 new helpers::EventResponseDelta(extension_id, extension_install_time));
871 result->deleted_request_headers.push_back(name_);
872 return result;
876 // WebRequestAddResponseHeaderAction
879 WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction(
880 const std::string& name,
881 const std::string& value)
882 : WebRequestAction(ON_HEADERS_RECEIVED,
883 ACTION_ADD_RESPONSE_HEADER,
884 std::numeric_limits<int>::min(),
885 STRATEGY_DEFAULT),
886 name_(name),
887 value_(value) {}
889 WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {}
891 bool WebRequestAddResponseHeaderAction::Equals(
892 const WebRequestAction* other) const {
893 if (!WebRequestAction::Equals(other))
894 return false;
895 const WebRequestAddResponseHeaderAction* casted_other =
896 static_cast<const WebRequestAddResponseHeaderAction*>(other);
897 return name_ == casted_other->name_ && value_ == casted_other->value_;
900 std::string WebRequestAddResponseHeaderAction::GetName() const {
901 return keys::kAddResponseHeaderType;
904 LinkedPtrEventResponseDelta
905 WebRequestAddResponseHeaderAction::CreateDelta(
906 const WebRequestData& request_data,
907 const std::string& extension_id,
908 const base::Time& extension_install_time) const {
909 CHECK(request_data.stage & stages());
910 const net::HttpResponseHeaders* headers =
911 request_data.original_response_headers;
912 if (!headers)
913 return LinkedPtrEventResponseDelta(NULL);
915 // Don't generate the header if it exists already.
916 if (headers->HasHeaderValue(name_, value_))
917 return LinkedPtrEventResponseDelta(NULL);
919 LinkedPtrEventResponseDelta result(
920 new helpers::EventResponseDelta(extension_id, extension_install_time));
921 result->added_response_headers.push_back(make_pair(name_, value_));
922 return result;
926 // WebRequestRemoveResponseHeaderAction
929 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction(
930 const std::string& name,
931 const std::string& value,
932 bool has_value)
933 : WebRequestAction(ON_HEADERS_RECEIVED,
934 ACTION_REMOVE_RESPONSE_HEADER,
935 std::numeric_limits<int>::min(),
936 STRATEGY_DEFAULT),
937 name_(name),
938 value_(value),
939 has_value_(has_value) {}
941 WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {}
943 bool WebRequestRemoveResponseHeaderAction::Equals(
944 const WebRequestAction* other) const {
945 if (!WebRequestAction::Equals(other))
946 return false;
947 const WebRequestRemoveResponseHeaderAction* casted_other =
948 static_cast<const WebRequestRemoveResponseHeaderAction*>(other);
949 return name_ == casted_other->name_ && value_ == casted_other->value_ &&
950 has_value_ == casted_other->has_value_;
953 std::string WebRequestRemoveResponseHeaderAction::GetName() const {
954 return keys::kRemoveResponseHeaderType;
957 LinkedPtrEventResponseDelta
958 WebRequestRemoveResponseHeaderAction::CreateDelta(
959 const WebRequestData& request_data,
960 const std::string& extension_id,
961 const base::Time& extension_install_time) const {
962 CHECK(request_data.stage & stages());
963 const net::HttpResponseHeaders* headers =
964 request_data.original_response_headers;
965 if (!headers)
966 return LinkedPtrEventResponseDelta(NULL);
968 LinkedPtrEventResponseDelta result(
969 new helpers::EventResponseDelta(extension_id, extension_install_time));
970 void* iter = NULL;
971 std::string current_value;
972 while (headers->EnumerateHeader(&iter, name_, &current_value)) {
973 if (has_value_ &&
974 (current_value.size() != value_.size() ||
975 !std::equal(current_value.begin(), current_value.end(),
976 value_.begin(),
977 base::CaseInsensitiveCompare<char>()))) {
978 continue;
980 result->deleted_response_headers.push_back(make_pair(name_, current_value));
982 return result;
986 // WebRequestIgnoreRulesAction
989 WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction(
990 int minimum_priority,
991 const std::string& ignore_tag)
992 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
993 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
994 ACTION_IGNORE_RULES,
995 minimum_priority,
996 STRATEGY_NONE),
997 ignore_tag_(ignore_tag) {}
999 WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {}
1001 bool WebRequestIgnoreRulesAction::Equals(const WebRequestAction* other) const {
1002 if (!WebRequestAction::Equals(other))
1003 return false;
1004 const WebRequestIgnoreRulesAction* casted_other =
1005 static_cast<const WebRequestIgnoreRulesAction*>(other);
1006 return minimum_priority() == casted_other->minimum_priority() &&
1007 ignore_tag_ == casted_other->ignore_tag_;
1010 std::string WebRequestIgnoreRulesAction::GetName() const {
1011 return keys::kIgnoreRulesType;
1014 LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta(
1015 const WebRequestData& request_data,
1016 const std::string& extension_id,
1017 const base::Time& extension_install_time) const {
1018 CHECK(request_data.stage & stages());
1019 return LinkedPtrEventResponseDelta(NULL);
1023 // WebRequestRequestCookieAction
1026 WebRequestRequestCookieAction::WebRequestRequestCookieAction(
1027 linked_ptr<RequestCookieModification> request_cookie_modification)
1028 : WebRequestAction(ON_BEFORE_SEND_HEADERS,
1029 ACTION_MODIFY_REQUEST_COOKIE,
1030 std::numeric_limits<int>::min(),
1031 STRATEGY_DEFAULT),
1032 request_cookie_modification_(request_cookie_modification) {
1033 CHECK(request_cookie_modification_.get());
1036 WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
1038 bool WebRequestRequestCookieAction::Equals(
1039 const WebRequestAction* other) const {
1040 if (!WebRequestAction::Equals(other))
1041 return false;
1042 const WebRequestRequestCookieAction* casted_other =
1043 static_cast<const WebRequestRequestCookieAction*>(other);
1044 return helpers::NullableEquals(
1045 request_cookie_modification_.get(),
1046 casted_other->request_cookie_modification_.get());
1049 std::string WebRequestRequestCookieAction::GetName() const {
1050 switch (request_cookie_modification_->type) {
1051 case helpers::ADD:
1052 return keys::kAddRequestCookieType;
1053 case helpers::EDIT:
1054 return keys::kEditRequestCookieType;
1055 case helpers::REMOVE:
1056 return keys::kRemoveRequestCookieType;
1058 NOTREACHED();
1059 return "";
1062 LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta(
1063 const WebRequestData& request_data,
1064 const std::string& extension_id,
1065 const base::Time& extension_install_time) const {
1066 CHECK(request_data.stage & stages());
1067 LinkedPtrEventResponseDelta result(
1068 new extension_web_request_api_helpers::EventResponseDelta(
1069 extension_id, extension_install_time));
1070 result->request_cookie_modifications.push_back(
1071 request_cookie_modification_);
1072 return result;
1076 // WebRequestResponseCookieAction
1079 WebRequestResponseCookieAction::WebRequestResponseCookieAction(
1080 linked_ptr<ResponseCookieModification> response_cookie_modification)
1081 : WebRequestAction(ON_HEADERS_RECEIVED,
1082 ACTION_MODIFY_RESPONSE_COOKIE,
1083 std::numeric_limits<int>::min(),
1084 STRATEGY_DEFAULT),
1085 response_cookie_modification_(response_cookie_modification) {
1086 CHECK(response_cookie_modification_.get());
1089 WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
1091 bool WebRequestResponseCookieAction::Equals(
1092 const WebRequestAction* other) const {
1093 if (!WebRequestAction::Equals(other))
1094 return false;
1095 const WebRequestResponseCookieAction* casted_other =
1096 static_cast<const WebRequestResponseCookieAction*>(other);
1097 return helpers::NullableEquals(
1098 response_cookie_modification_.get(),
1099 casted_other->response_cookie_modification_.get());
1102 std::string WebRequestResponseCookieAction::GetName() const {
1103 switch (response_cookie_modification_->type) {
1104 case helpers::ADD:
1105 return keys::kAddResponseCookieType;
1106 case helpers::EDIT:
1107 return keys::kEditResponseCookieType;
1108 case helpers::REMOVE:
1109 return keys::kRemoveResponseCookieType;
1111 NOTREACHED();
1112 return "";
1115 LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta(
1116 const WebRequestData& request_data,
1117 const std::string& extension_id,
1118 const base::Time& extension_install_time) const {
1119 CHECK(request_data.stage & stages());
1120 LinkedPtrEventResponseDelta result(
1121 new extension_web_request_api_helpers::EventResponseDelta(
1122 extension_id, extension_install_time));
1123 result->response_cookie_modifications.push_back(
1124 response_cookie_modification_);
1125 return result;
1129 // WebRequestSendMessageToExtensionAction
1132 WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction(
1133 const std::string& message)
1134 : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS |
1135 ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED,
1136 ACTION_SEND_MESSAGE_TO_EXTENSION,
1137 std::numeric_limits<int>::min(),
1138 STRATEGY_HOST),
1139 message_(message) {}
1141 WebRequestSendMessageToExtensionAction::
1142 ~WebRequestSendMessageToExtensionAction() {}
1144 bool WebRequestSendMessageToExtensionAction::Equals(
1145 const WebRequestAction* other) const {
1146 if (!WebRequestAction::Equals(other))
1147 return false;
1148 const WebRequestSendMessageToExtensionAction* casted_other =
1149 static_cast<const WebRequestSendMessageToExtensionAction*>(other);
1150 return message_ == casted_other->message_;
1153 std::string WebRequestSendMessageToExtensionAction::GetName() const {
1154 return keys::kSendMessageToExtensionType;
1157 LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta(
1158 const WebRequestData& request_data,
1159 const std::string& extension_id,
1160 const base::Time& extension_install_time) const {
1161 CHECK(request_data.stage & stages());
1162 LinkedPtrEventResponseDelta result(
1163 new extension_web_request_api_helpers::EventResponseDelta(
1164 extension_id, extension_install_time));
1165 result->messages_to_extension.insert(message_);
1166 return result;
1169 } // namespace extensions