|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "extensions/browser/api/declarative_webrequest/webrequest_action.h" | 
|  |  | 
|  | #include <limits> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "base/values.h" | 
|  | #include "content/public/browser/resource_request_info.h" | 
|  | #include "content/public/common/url_constants.h" | 
|  | #include "extensions/browser/api/declarative/deduping_factory.h" | 
|  | #include "extensions/browser/api/declarative_webrequest/request_stage.h" | 
|  | #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h" | 
|  | #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" | 
|  | #include "extensions/browser/api/web_request/web_request_api_constants.h" | 
|  | #include "extensions/browser/api/web_request/web_request_api_helpers.h" | 
|  | #include "extensions/browser/api/web_request/web_request_permissions.h" | 
|  | #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" | 
|  | #include "extensions/browser/info_map.h" | 
|  | #include "extensions/common/error_utils.h" | 
|  | #include "extensions/common/extension.h" | 
|  | #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 
|  | #include "net/http/http_util.h" | 
|  | #include "net/url_request/url_request.h" | 
|  | #include "third_party/re2/src/re2/re2.h" | 
|  |  | 
|  | using content::ResourceRequestInfo; | 
|  |  | 
|  | namespace extensions { | 
|  |  | 
|  | namespace helpers = extension_web_request_api_helpers; | 
|  | namespace keys = declarative_webrequest_constants; | 
|  |  | 
|  | namespace { | 
|  | // Error messages. | 
|  | const char kIgnoreRulesRequiresParameterError[] = | 
|  | "IgnoreRules requires at least one parameter."; | 
|  |  | 
|  | const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh" | 
|  | "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="; | 
|  | const char kEmptyDocumentUrl[] = "data:text/html,"; | 
|  |  | 
|  | #define INPUT_FORMAT_VALIDATE(test) do { \ | 
|  | if (!(test)) { \ | 
|  | *bad_message = true; \ | 
|  | return scoped_refptr<const WebRequestAction>(NULL); \ | 
|  | } \ | 
|  | } while (0) | 
|  |  | 
|  | std::unique_ptr<helpers::RequestCookie> ParseRequestCookie( | 
|  | const base::DictionaryValue* dict) { | 
|  | std::unique_ptr<helpers::RequestCookie> result(new helpers::RequestCookie); | 
|  | std::string tmp; | 
|  | if (dict->GetString(keys::kNameKey, &tmp)) | 
|  | result->name.reset(new std::string(tmp)); | 
|  | if (dict->GetString(keys::kValueKey, &tmp)) | 
|  | result->value.reset(new std::string(tmp)); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | void ParseResponseCookieImpl(const base::DictionaryValue* dict, | 
|  | helpers::ResponseCookie* cookie) { | 
|  | std::string string_tmp; | 
|  | int int_tmp = 0; | 
|  | bool bool_tmp = false; | 
|  | if (dict->GetString(keys::kNameKey, &string_tmp)) | 
|  | cookie->name.reset(new std::string(string_tmp)); | 
|  | if (dict->GetString(keys::kValueKey, &string_tmp)) | 
|  | cookie->value.reset(new std::string(string_tmp)); | 
|  | if (dict->GetString(keys::kExpiresKey, &string_tmp)) | 
|  | cookie->expires.reset(new std::string(string_tmp)); | 
|  | if (dict->GetInteger(keys::kMaxAgeKey, &int_tmp)) | 
|  | cookie->max_age.reset(new int(int_tmp)); | 
|  | if (dict->GetString(keys::kDomainKey, &string_tmp)) | 
|  | cookie->domain.reset(new std::string(string_tmp)); | 
|  | if (dict->GetString(keys::kPathKey, &string_tmp)) | 
|  | cookie->path.reset(new std::string(string_tmp)); | 
|  | if (dict->GetBoolean(keys::kSecureKey, &bool_tmp)) | 
|  | cookie->secure.reset(new bool(bool_tmp)); | 
|  | if (dict->GetBoolean(keys::kHttpOnlyKey, &bool_tmp)) | 
|  | cookie->http_only.reset(new bool(bool_tmp)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<helpers::ResponseCookie> ParseResponseCookie( | 
|  | const base::DictionaryValue* dict) { | 
|  | std::unique_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie); | 
|  | ParseResponseCookieImpl(dict, result.get()); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<helpers::FilterResponseCookie> ParseFilterResponseCookie( | 
|  | const base::DictionaryValue* dict) { | 
|  | std::unique_ptr<helpers::FilterResponseCookie> result( | 
|  | new helpers::FilterResponseCookie); | 
|  | ParseResponseCookieImpl(dict, result.get()); | 
|  |  | 
|  | int int_tmp = 0; | 
|  | bool bool_tmp = false; | 
|  | if (dict->GetInteger(keys::kAgeUpperBoundKey, &int_tmp)) | 
|  | result->age_upper_bound.reset(new int(int_tmp)); | 
|  | if (dict->GetInteger(keys::kAgeLowerBoundKey, &int_tmp)) | 
|  | result->age_lower_bound.reset(new int(int_tmp)); | 
|  | if (dict->GetBoolean(keys::kSessionCookieKey, &bool_tmp)) | 
|  | result->session_cookie.reset(new bool(bool_tmp)); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // Helper function for WebRequestActions that can be instantiated by just | 
|  | // calling the constructor. | 
|  | template <class T> | 
|  | scoped_refptr<const WebRequestAction> CallConstructorFactoryMethod( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | return scoped_refptr<const WebRequestAction>(new T); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateRedirectRequestAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  | std::string redirect_url_string; | 
|  | INPUT_FORMAT_VALIDATE( | 
|  | dict->GetString(keys::kRedirectUrlKey, &redirect_url_string)); | 
|  | GURL redirect_url(redirect_url_string); | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestRedirectAction(redirect_url)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateRedirectRequestByRegExAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  | std::string from; | 
|  | std::string to; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from)); | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to)); | 
|  |  | 
|  | to = WebRequestRedirectByRegExAction::PerlToRe2Style(to); | 
|  |  | 
|  | RE2::Options options; | 
|  | options.set_case_sensitive(false); | 
|  | std::unique_ptr<RE2> from_pattern(new RE2(from, options)); | 
|  |  | 
|  | if (!from_pattern->ok()) { | 
|  | *error = "Invalid pattern '" + from + "' -> '" + to + "'"; | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestRedirectByRegExAction(std::move(from_pattern), to)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateSetRequestHeaderAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* json_value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(json_value->GetAsDictionary(&dict)); | 
|  | std::string name; | 
|  | std::string value; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value)); | 
|  | if (!net::HttpUtil::IsValidHeaderName(name)) { | 
|  | *error = extension_web_request_api_constants::kInvalidHeaderName; | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | if (!net::HttpUtil::IsValidHeaderValue(value)) { | 
|  | *error = ErrorUtils::FormatErrorMessage( | 
|  | extension_web_request_api_constants::kInvalidHeaderValue, name); | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestSetRequestHeaderAction(name, value)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateRemoveRequestHeaderAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  | std::string name; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); | 
|  | if (!net::HttpUtil::IsValidHeaderName(name)) { | 
|  | *error = extension_web_request_api_constants::kInvalidHeaderName; | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestRemoveRequestHeaderAction(name)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateAddResponseHeaderAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* json_value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(json_value->GetAsDictionary(&dict)); | 
|  | std::string name; | 
|  | std::string value; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value)); | 
|  | if (!net::HttpUtil::IsValidHeaderName(name)) { | 
|  | *error = extension_web_request_api_constants::kInvalidHeaderName; | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | if (!net::HttpUtil::IsValidHeaderValue(value)) { | 
|  | *error = ErrorUtils::FormatErrorMessage( | 
|  | extension_web_request_api_constants::kInvalidHeaderValue, name); | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestAddResponseHeaderAction(name, value)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateRemoveResponseHeaderAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* json_value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(json_value->GetAsDictionary(&dict)); | 
|  | std::string name; | 
|  | std::string value; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); | 
|  | bool has_value = dict->GetString(keys::kValueKey, &value); | 
|  | if (!net::HttpUtil::IsValidHeaderName(name)) { | 
|  | *error = extension_web_request_api_constants::kInvalidHeaderName; | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | if (has_value && !net::HttpUtil::IsValidHeaderValue(value)) { | 
|  | *error = ErrorUtils::FormatErrorMessage( | 
|  | extension_web_request_api_constants::kInvalidHeaderValue, name); | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestRemoveResponseHeaderAction(name, value, has_value)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateIgnoreRulesAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  | bool has_parameter = false; | 
|  | int minimum_priority = std::numeric_limits<int>::min(); | 
|  | std::string ignore_tag; | 
|  | if (dict->HasKey(keys::kLowerPriorityThanKey)) { | 
|  | INPUT_FORMAT_VALIDATE( | 
|  | dict->GetInteger(keys::kLowerPriorityThanKey, &minimum_priority)); | 
|  | has_parameter = true; | 
|  | } | 
|  | if (dict->HasKey(keys::kHasTagKey)) { | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kHasTagKey, &ignore_tag)); | 
|  | has_parameter = true; | 
|  | } | 
|  | if (!has_parameter) { | 
|  | *error = kIgnoreRulesRequiresParameterError; | 
|  | return scoped_refptr<const WebRequestAction>(NULL); | 
|  | } | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestIgnoreRulesAction(minimum_priority, ignore_tag)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateRequestCookieAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | using extension_web_request_api_helpers::RequestCookieModification; | 
|  |  | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  |  | 
|  | linked_ptr<RequestCookieModification> modification( | 
|  | new RequestCookieModification); | 
|  |  | 
|  | // Get modification type. | 
|  | if (instance_type == keys::kAddRequestCookieType) | 
|  | modification->type = helpers::ADD; | 
|  | else if (instance_type == keys::kEditRequestCookieType) | 
|  | modification->type = helpers::EDIT; | 
|  | else if (instance_type == keys::kRemoveRequestCookieType) | 
|  | modification->type = helpers::REMOVE; | 
|  | else | 
|  | INPUT_FORMAT_VALIDATE(false); | 
|  |  | 
|  | // Get filter. | 
|  | if (modification->type == helpers::EDIT || | 
|  | modification->type == helpers::REMOVE) { | 
|  | const base::DictionaryValue* filter = NULL; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter)); | 
|  | modification->filter = ParseRequestCookie(filter); | 
|  | } | 
|  |  | 
|  | // Get new value. | 
|  | if (modification->type == helpers::ADD) { | 
|  | const base::DictionaryValue* value = NULL; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value)); | 
|  | modification->modification = ParseRequestCookie(value); | 
|  | } else if (modification->type == helpers::EDIT) { | 
|  | const base::DictionaryValue* value = NULL; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value)); | 
|  | modification->modification = ParseRequestCookie(value); | 
|  | } | 
|  |  | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestRequestCookieAction(modification)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateResponseCookieAction( | 
|  | const std::string& instance_type, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | using extension_web_request_api_helpers::ResponseCookieModification; | 
|  |  | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  |  | 
|  | linked_ptr<ResponseCookieModification> modification( | 
|  | new ResponseCookieModification); | 
|  |  | 
|  | // Get modification type. | 
|  | if (instance_type == keys::kAddResponseCookieType) | 
|  | modification->type = helpers::ADD; | 
|  | else if (instance_type == keys::kEditResponseCookieType) | 
|  | modification->type = helpers::EDIT; | 
|  | else if (instance_type == keys::kRemoveResponseCookieType) | 
|  | modification->type = helpers::REMOVE; | 
|  | else | 
|  | INPUT_FORMAT_VALIDATE(false); | 
|  |  | 
|  | // Get filter. | 
|  | if (modification->type == helpers::EDIT || | 
|  | modification->type == helpers::REMOVE) { | 
|  | const base::DictionaryValue* filter = NULL; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter)); | 
|  | modification->filter = ParseFilterResponseCookie(filter); | 
|  | } | 
|  |  | 
|  | // Get new value. | 
|  | if (modification->type == helpers::ADD) { | 
|  | const base::DictionaryValue* value = NULL; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value)); | 
|  | modification->modification = ParseResponseCookie(value); | 
|  | } else if (modification->type == helpers::EDIT) { | 
|  | const base::DictionaryValue* value = NULL; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value)); | 
|  | modification->modification = ParseResponseCookie(value); | 
|  | } | 
|  |  | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestResponseCookieAction(modification)); | 
|  | } | 
|  |  | 
|  | scoped_refptr<const WebRequestAction> CreateSendMessageToExtensionAction( | 
|  | const std::string& name, | 
|  | const base::Value* value, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | const base::DictionaryValue* dict = NULL; | 
|  | CHECK(value->GetAsDictionary(&dict)); | 
|  | std::string message; | 
|  | INPUT_FORMAT_VALIDATE(dict->GetString(keys::kMessageKey, &message)); | 
|  | return scoped_refptr<const WebRequestAction>( | 
|  | new WebRequestSendMessageToExtensionAction(message)); | 
|  | } | 
|  |  | 
|  | struct WebRequestActionFactory { | 
|  | DedupingFactory<WebRequestAction> factory; | 
|  |  | 
|  | WebRequestActionFactory() : factory(5) { | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kAddRequestCookieType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRequestCookieAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kAddResponseCookieType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateResponseCookieAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kAddResponseHeaderType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateAddResponseHeaderAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kCancelRequestType, | 
|  | DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED, | 
|  | &CallConstructorFactoryMethod<WebRequestCancelAction>); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kEditRequestCookieType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRequestCookieAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kEditResponseCookieType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateResponseCookieAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRedirectByRegExType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRedirectRequestByRegExAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRedirectRequestType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRedirectRequestAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRedirectToTransparentImageType, | 
|  | DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED, | 
|  | &CallConstructorFactoryMethod< | 
|  | WebRequestRedirectToTransparentImageAction>); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRedirectToEmptyDocumentType, | 
|  | DedupingFactory<WebRequestAction>::IS_NOT_PARAMETERIZED, | 
|  | &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRemoveRequestCookieType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRequestCookieAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRemoveResponseCookieType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateResponseCookieAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kSetRequestHeaderType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateSetRequestHeaderAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRemoveRequestHeaderType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRemoveRequestHeaderAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kRemoveResponseHeaderType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateRemoveResponseHeaderAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kIgnoreRulesType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateIgnoreRulesAction); | 
|  | factory.RegisterFactoryMethod( | 
|  | keys::kSendMessageToExtensionType, | 
|  | DedupingFactory<WebRequestAction>::IS_PARAMETERIZED, | 
|  | &CreateSendMessageToExtensionAction); | 
|  | } | 
|  | }; | 
|  |  | 
|  | base::LazyInstance<WebRequestActionFactory>::Leaky | 
|  | g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // | 
|  | // WebRequestAction | 
|  | // | 
|  |  | 
|  | WebRequestAction::~WebRequestAction() {} | 
|  |  | 
|  | bool WebRequestAction::Equals(const WebRequestAction* other) const { | 
|  | return type() == other->type(); | 
|  | } | 
|  |  | 
|  | bool WebRequestAction::HasPermission(const InfoMap* extension_info_map, | 
|  | const std::string& extension_id, | 
|  | const net::URLRequest* request, | 
|  | bool crosses_incognito) const { | 
|  | if (WebRequestPermissions::HideRequest(extension_info_map, request)) | 
|  | return false; | 
|  |  | 
|  | // In unit tests we don't have an extension_info_map object here and skip host | 
|  | // permission checks. | 
|  | if (!extension_info_map) | 
|  | return true; | 
|  |  | 
|  | const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); | 
|  | int process_id = info ? info->GetChildID() : 0; | 
|  |  | 
|  | // The embedder can always access all hosts from within a <webview>. | 
|  | // The same is not true of extensions. | 
|  | if (WebViewRendererState::GetInstance()->IsGuest(process_id)) | 
|  | return true; | 
|  |  | 
|  | WebRequestPermissions::HostPermissionsCheck permission_check = | 
|  | WebRequestPermissions::REQUIRE_ALL_URLS; | 
|  | switch (host_permissions_strategy()) { | 
|  | case STRATEGY_DEFAULT:  // Default value is already set. | 
|  | break; | 
|  | case STRATEGY_NONE: | 
|  | permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST; | 
|  | break; | 
|  | case STRATEGY_HOST: | 
|  | permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION; | 
|  | break; | 
|  | } | 
|  | // TODO(devlin): Pass in the real tab id here. | 
|  | return WebRequestPermissions::CanExtensionAccessURL( | 
|  | extension_info_map, extension_id, request->url(), -1, | 
|  | crosses_incognito, | 
|  | permission_check) == PermissionsData::ACCESS_ALLOWED; | 
|  | } | 
|  |  | 
|  | // static | 
|  | scoped_refptr<const WebRequestAction> WebRequestAction::Create( | 
|  | content::BrowserContext* browser_context, | 
|  | const Extension* extension, | 
|  | const base::Value& json_action, | 
|  | std::string* error, | 
|  | bool* bad_message) { | 
|  | *error = ""; | 
|  | *bad_message = false; | 
|  |  | 
|  | const base::DictionaryValue* action_dict = NULL; | 
|  | INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict)); | 
|  |  | 
|  | std::string instance_type; | 
|  | INPUT_FORMAT_VALIDATE( | 
|  | action_dict->GetString(keys::kInstanceTypeKey, &instance_type)); | 
|  |  | 
|  | WebRequestActionFactory& factory = g_web_request_action_factory.Get(); | 
|  | return factory.factory.Instantiate( | 
|  | instance_type, action_dict, error, bad_message); | 
|  | } | 
|  |  | 
|  | void WebRequestAction::Apply(const std::string& extension_id, | 
|  | base::Time extension_install_time, | 
|  | ApplyInfo* apply_info) const { | 
|  | if (!HasPermission(apply_info->extension_info_map, extension_id, | 
|  | apply_info->request_data.request, | 
|  | apply_info->crosses_incognito)) | 
|  | return; | 
|  | if (stages() & apply_info->request_data.stage) { | 
|  | LinkedPtrEventResponseDelta delta = CreateDelta( | 
|  | apply_info->request_data, extension_id, extension_install_time); | 
|  | if (delta.get()) | 
|  | apply_info->deltas->push_back(delta); | 
|  | if (type() == WebRequestAction::ACTION_IGNORE_RULES) { | 
|  | const WebRequestIgnoreRulesAction* ignore_action = | 
|  | static_cast<const WebRequestIgnoreRulesAction*>(this); | 
|  | if (!ignore_action->ignore_tag().empty()) | 
|  | apply_info->ignored_tags->insert(ignore_action->ignore_tag()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | WebRequestAction::WebRequestAction(int stages, | 
|  | Type type, | 
|  | int minimum_priority, | 
|  | HostPermissionsStrategy strategy) | 
|  | : stages_(stages), | 
|  | type_(type), | 
|  | minimum_priority_(minimum_priority), | 
|  | host_permissions_strategy_(strategy) {} | 
|  |  | 
|  | // | 
|  | // WebRequestCancelAction | 
|  | // | 
|  |  | 
|  | WebRequestCancelAction::WebRequestCancelAction() | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | | 
|  | ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED, | 
|  | ACTION_CANCEL_REQUEST, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_NONE) {} | 
|  |  | 
|  | WebRequestCancelAction::~WebRequestCancelAction() {} | 
|  |  | 
|  | std::string WebRequestCancelAction::GetName() const { | 
|  | return keys::kCancelRequestType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestCancelAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->cancel = true; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRedirectAction | 
|  | // | 
|  |  | 
|  | WebRequestRedirectAction::WebRequestRedirectAction(const GURL& redirect_url) | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED, | 
|  | ACTION_REDIRECT_REQUEST, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | redirect_url_(redirect_url) {} | 
|  |  | 
|  | WebRequestRedirectAction::~WebRequestRedirectAction() {} | 
|  |  | 
|  | bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const { | 
|  | return WebRequestAction::Equals(other) && | 
|  | redirect_url_ == | 
|  | static_cast<const WebRequestRedirectAction*>(other)->redirect_url_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestRedirectAction::GetName() const { | 
|  | return keys::kRedirectRequestType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestRedirectAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | if (request_data.request->url() == redirect_url_) | 
|  | return LinkedPtrEventResponseDelta(NULL); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->new_url = redirect_url_; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRedirectToTransparentImageAction | 
|  | // | 
|  |  | 
|  | WebRequestRedirectToTransparentImageAction:: | 
|  | WebRequestRedirectToTransparentImageAction() | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED, | 
|  | ACTION_REDIRECT_TO_TRANSPARENT_IMAGE, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_NONE) {} | 
|  |  | 
|  | WebRequestRedirectToTransparentImageAction:: | 
|  | ~WebRequestRedirectToTransparentImageAction() {} | 
|  |  | 
|  | std::string WebRequestRedirectToTransparentImageAction::GetName() const { | 
|  | return keys::kRedirectToTransparentImageType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta | 
|  | WebRequestRedirectToTransparentImageAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->new_url = GURL(kTransparentImageUrl); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRedirectToEmptyDocumentAction | 
|  | // | 
|  |  | 
|  | WebRequestRedirectToEmptyDocumentAction:: | 
|  | WebRequestRedirectToEmptyDocumentAction() | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED, | 
|  | ACTION_REDIRECT_TO_EMPTY_DOCUMENT, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_NONE) {} | 
|  |  | 
|  | WebRequestRedirectToEmptyDocumentAction:: | 
|  | ~WebRequestRedirectToEmptyDocumentAction() {} | 
|  |  | 
|  | std::string WebRequestRedirectToEmptyDocumentAction::GetName() const { | 
|  | return keys::kRedirectToEmptyDocumentType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta | 
|  | WebRequestRedirectToEmptyDocumentAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->new_url = GURL(kEmptyDocumentUrl); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRedirectByRegExAction | 
|  | // | 
|  |  | 
|  | WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction( | 
|  | std::unique_ptr<RE2> from_pattern, | 
|  | const std::string& to_pattern) | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_HEADERS_RECEIVED, | 
|  | ACTION_REDIRECT_BY_REGEX_DOCUMENT, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | from_pattern_(std::move(from_pattern)), | 
|  | to_pattern_(to_pattern.data(), to_pattern.size()) {} | 
|  |  | 
|  | WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {} | 
|  |  | 
|  | // About the syntax of the two languages: | 
|  | // | 
|  | // ICU (Perl) states: | 
|  | // $n The text of capture group n will be substituted for $n. n must be >= 0 | 
|  | //    and not greater than the number of capture groups. A $ not followed by a | 
|  | //    digit has no special meaning, and will appear in the substitution text | 
|  | //    as itself, a $. | 
|  | // \  Treat the following character as a literal, suppressing any special | 
|  | //    meaning. Backslash escaping in substitution text is only required for | 
|  | //    '$' and '\', but may be used on any other character without bad effects. | 
|  | // | 
|  | // RE2, derived from RE2::Rewrite() | 
|  | // \  May only be followed by a digit or another \. If followed by a single | 
|  | //    digit, both characters represent the respective capture group. If followed | 
|  | //    by another \, it is used as an escape sequence. | 
|  |  | 
|  | // static | 
|  | std::string WebRequestRedirectByRegExAction::PerlToRe2Style( | 
|  | const std::string& perl) { | 
|  | std::string::const_iterator i = perl.begin(); | 
|  | std::string result; | 
|  | while (i != perl.end()) { | 
|  | if (*i == '$') { | 
|  | ++i; | 
|  | if (i == perl.end()) { | 
|  | result += '$'; | 
|  | return result; | 
|  | } else if (isdigit(*i)) { | 
|  | result += '\\'; | 
|  | result += *i; | 
|  | } else { | 
|  | result += '$'; | 
|  | result += *i; | 
|  | } | 
|  | } else if (*i == '\\') { | 
|  | ++i; | 
|  | if (i == perl.end()) { | 
|  | result += '\\'; | 
|  | } else if (*i == '$') { | 
|  | result += '$'; | 
|  | } else if (*i == '\\') { | 
|  | result += "\\\\"; | 
|  | } else { | 
|  | result += *i; | 
|  | } | 
|  | } else { | 
|  | result += *i; | 
|  | } | 
|  | ++i; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool WebRequestRedirectByRegExAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestRedirectByRegExAction* casted_other = | 
|  | static_cast<const WebRequestRedirectByRegExAction*>(other); | 
|  | return from_pattern_->pattern() == casted_other->from_pattern_->pattern() && | 
|  | to_pattern_ == casted_other->to_pattern_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestRedirectByRegExAction::GetName() const { | 
|  | return keys::kRedirectByRegExType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | CHECK(from_pattern_.get()); | 
|  |  | 
|  | const std::string& old_url = request_data.request->url().spec(); | 
|  | std::string new_url = old_url; | 
|  | if (!RE2::Replace(&new_url, *from_pattern_, to_pattern_) || | 
|  | new_url == old_url) { | 
|  | return LinkedPtrEventResponseDelta(NULL); | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new extension_web_request_api_helpers::EventResponseDelta( | 
|  | extension_id, extension_install_time)); | 
|  | result->new_url = GURL(new_url); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestSetRequestHeaderAction | 
|  | // | 
|  |  | 
|  | WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction( | 
|  | const std::string& name, | 
|  | const std::string& value) | 
|  | : WebRequestAction(ON_BEFORE_SEND_HEADERS, | 
|  | ACTION_SET_REQUEST_HEADER, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | name_(name), | 
|  | value_(value) {} | 
|  |  | 
|  | WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {} | 
|  |  | 
|  | bool WebRequestSetRequestHeaderAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestSetRequestHeaderAction* casted_other = | 
|  | static_cast<const WebRequestSetRequestHeaderAction*>(other); | 
|  | return name_ == casted_other->name_ && value_ == casted_other->value_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestSetRequestHeaderAction::GetName() const { | 
|  | return keys::kSetRequestHeaderType; | 
|  | } | 
|  |  | 
|  |  | 
|  | LinkedPtrEventResponseDelta | 
|  | WebRequestSetRequestHeaderAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->modified_request_headers.SetHeader(name_, value_); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRemoveRequestHeaderAction | 
|  | // | 
|  |  | 
|  | WebRequestRemoveRequestHeaderAction::WebRequestRemoveRequestHeaderAction( | 
|  | const std::string& name) | 
|  | : WebRequestAction(ON_BEFORE_SEND_HEADERS, | 
|  | ACTION_REMOVE_REQUEST_HEADER, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | name_(name) {} | 
|  |  | 
|  | WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {} | 
|  |  | 
|  | bool WebRequestRemoveRequestHeaderAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestRemoveRequestHeaderAction* casted_other = | 
|  | static_cast<const WebRequestRemoveRequestHeaderAction*>(other); | 
|  | return name_ == casted_other->name_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestRemoveRequestHeaderAction::GetName() const { | 
|  | return keys::kRemoveRequestHeaderType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta | 
|  | WebRequestRemoveRequestHeaderAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->deleted_request_headers.push_back(name_); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestAddResponseHeaderAction | 
|  | // | 
|  |  | 
|  | WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction( | 
|  | const std::string& name, | 
|  | const std::string& value) | 
|  | : WebRequestAction(ON_HEADERS_RECEIVED, | 
|  | ACTION_ADD_RESPONSE_HEADER, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | name_(name), | 
|  | value_(value) {} | 
|  |  | 
|  | WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {} | 
|  |  | 
|  | bool WebRequestAddResponseHeaderAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestAddResponseHeaderAction* casted_other = | 
|  | static_cast<const WebRequestAddResponseHeaderAction*>(other); | 
|  | return name_ == casted_other->name_ && value_ == casted_other->value_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestAddResponseHeaderAction::GetName() const { | 
|  | return keys::kAddResponseHeaderType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta | 
|  | WebRequestAddResponseHeaderAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | const net::HttpResponseHeaders* headers = | 
|  | request_data.original_response_headers; | 
|  | if (!headers) | 
|  | return LinkedPtrEventResponseDelta(NULL); | 
|  |  | 
|  | // Don't generate the header if it exists already. | 
|  | if (headers->HasHeaderValue(name_, value_)) | 
|  | return LinkedPtrEventResponseDelta(NULL); | 
|  |  | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | result->added_response_headers.push_back(make_pair(name_, value_)); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRemoveResponseHeaderAction | 
|  | // | 
|  |  | 
|  | WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction( | 
|  | const std::string& name, | 
|  | const std::string& value, | 
|  | bool has_value) | 
|  | : WebRequestAction(ON_HEADERS_RECEIVED, | 
|  | ACTION_REMOVE_RESPONSE_HEADER, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | name_(name), | 
|  | value_(value), | 
|  | has_value_(has_value) {} | 
|  |  | 
|  | WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {} | 
|  |  | 
|  | bool WebRequestRemoveResponseHeaderAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestRemoveResponseHeaderAction* casted_other = | 
|  | static_cast<const WebRequestRemoveResponseHeaderAction*>(other); | 
|  | return name_ == casted_other->name_ && value_ == casted_other->value_ && | 
|  | has_value_ == casted_other->has_value_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestRemoveResponseHeaderAction::GetName() const { | 
|  | return keys::kRemoveResponseHeaderType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta | 
|  | WebRequestRemoveResponseHeaderAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | const net::HttpResponseHeaders* headers = | 
|  | request_data.original_response_headers; | 
|  | if (!headers) | 
|  | return LinkedPtrEventResponseDelta(NULL); | 
|  |  | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new helpers::EventResponseDelta(extension_id, extension_install_time)); | 
|  | size_t iter = 0; | 
|  | std::string current_value; | 
|  | while (headers->EnumerateHeader(&iter, name_, ¤t_value)) { | 
|  | if (has_value_ && !base::EqualsCaseInsensitiveASCII(current_value, value_)) | 
|  | continue; | 
|  | result->deleted_response_headers.push_back(make_pair(name_, current_value)); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestIgnoreRulesAction | 
|  | // | 
|  |  | 
|  | WebRequestIgnoreRulesAction::WebRequestIgnoreRulesAction( | 
|  | int minimum_priority, | 
|  | const std::string& ignore_tag) | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | | 
|  | ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED, | 
|  | ACTION_IGNORE_RULES, | 
|  | minimum_priority, | 
|  | STRATEGY_NONE), | 
|  | ignore_tag_(ignore_tag) {} | 
|  |  | 
|  | WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {} | 
|  |  | 
|  | bool WebRequestIgnoreRulesAction::Equals(const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestIgnoreRulesAction* casted_other = | 
|  | static_cast<const WebRequestIgnoreRulesAction*>(other); | 
|  | return minimum_priority() == casted_other->minimum_priority() && | 
|  | ignore_tag_ == casted_other->ignore_tag_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestIgnoreRulesAction::GetName() const { | 
|  | return keys::kIgnoreRulesType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | return LinkedPtrEventResponseDelta(NULL); | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestRequestCookieAction | 
|  | // | 
|  |  | 
|  | WebRequestRequestCookieAction::WebRequestRequestCookieAction( | 
|  | linked_ptr<RequestCookieModification> request_cookie_modification) | 
|  | : WebRequestAction(ON_BEFORE_SEND_HEADERS, | 
|  | ACTION_MODIFY_REQUEST_COOKIE, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | request_cookie_modification_(request_cookie_modification) { | 
|  | CHECK(request_cookie_modification_.get()); | 
|  | } | 
|  |  | 
|  | WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {} | 
|  |  | 
|  | bool WebRequestRequestCookieAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestRequestCookieAction* casted_other = | 
|  | static_cast<const WebRequestRequestCookieAction*>(other); | 
|  | return helpers::NullableEquals( | 
|  | request_cookie_modification_.get(), | 
|  | casted_other->request_cookie_modification_.get()); | 
|  | } | 
|  |  | 
|  | std::string WebRequestRequestCookieAction::GetName() const { | 
|  | switch (request_cookie_modification_->type) { | 
|  | case helpers::ADD: | 
|  | return keys::kAddRequestCookieType; | 
|  | case helpers::EDIT: | 
|  | return keys::kEditRequestCookieType; | 
|  | case helpers::REMOVE: | 
|  | return keys::kRemoveRequestCookieType; | 
|  | } | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new extension_web_request_api_helpers::EventResponseDelta( | 
|  | extension_id, extension_install_time)); | 
|  | result->request_cookie_modifications.push_back( | 
|  | request_cookie_modification_); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestResponseCookieAction | 
|  | // | 
|  |  | 
|  | WebRequestResponseCookieAction::WebRequestResponseCookieAction( | 
|  | linked_ptr<ResponseCookieModification> response_cookie_modification) | 
|  | : WebRequestAction(ON_HEADERS_RECEIVED, | 
|  | ACTION_MODIFY_RESPONSE_COOKIE, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_DEFAULT), | 
|  | response_cookie_modification_(response_cookie_modification) { | 
|  | CHECK(response_cookie_modification_.get()); | 
|  | } | 
|  |  | 
|  | WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {} | 
|  |  | 
|  | bool WebRequestResponseCookieAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestResponseCookieAction* casted_other = | 
|  | static_cast<const WebRequestResponseCookieAction*>(other); | 
|  | return helpers::NullableEquals( | 
|  | response_cookie_modification_.get(), | 
|  | casted_other->response_cookie_modification_.get()); | 
|  | } | 
|  |  | 
|  | std::string WebRequestResponseCookieAction::GetName() const { | 
|  | switch (response_cookie_modification_->type) { | 
|  | case helpers::ADD: | 
|  | return keys::kAddResponseCookieType; | 
|  | case helpers::EDIT: | 
|  | return keys::kEditResponseCookieType; | 
|  | case helpers::REMOVE: | 
|  | return keys::kRemoveResponseCookieType; | 
|  | } | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new extension_web_request_api_helpers::EventResponseDelta( | 
|  | extension_id, extension_install_time)); | 
|  | result->response_cookie_modifications.push_back( | 
|  | response_cookie_modification_); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // | 
|  | // WebRequestSendMessageToExtensionAction | 
|  | // | 
|  |  | 
|  | WebRequestSendMessageToExtensionAction::WebRequestSendMessageToExtensionAction( | 
|  | const std::string& message) | 
|  | : WebRequestAction(ON_BEFORE_REQUEST | ON_BEFORE_SEND_HEADERS | | 
|  | ON_HEADERS_RECEIVED | ON_AUTH_REQUIRED, | 
|  | ACTION_SEND_MESSAGE_TO_EXTENSION, | 
|  | std::numeric_limits<int>::min(), | 
|  | STRATEGY_HOST), | 
|  | message_(message) {} | 
|  |  | 
|  | WebRequestSendMessageToExtensionAction:: | 
|  | ~WebRequestSendMessageToExtensionAction() {} | 
|  |  | 
|  | bool WebRequestSendMessageToExtensionAction::Equals( | 
|  | const WebRequestAction* other) const { | 
|  | if (!WebRequestAction::Equals(other)) | 
|  | return false; | 
|  | const WebRequestSendMessageToExtensionAction* casted_other = | 
|  | static_cast<const WebRequestSendMessageToExtensionAction*>(other); | 
|  | return message_ == casted_other->message_; | 
|  | } | 
|  |  | 
|  | std::string WebRequestSendMessageToExtensionAction::GetName() const { | 
|  | return keys::kSendMessageToExtensionType; | 
|  | } | 
|  |  | 
|  | LinkedPtrEventResponseDelta WebRequestSendMessageToExtensionAction::CreateDelta( | 
|  | const WebRequestData& request_data, | 
|  | const std::string& extension_id, | 
|  | const base::Time& extension_install_time) const { | 
|  | CHECK(request_data.stage & stages()); | 
|  | LinkedPtrEventResponseDelta result( | 
|  | new extension_web_request_api_helpers::EventResponseDelta( | 
|  | extension_id, extension_install_time)); | 
|  | result->messages_to_extension.insert(message_); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | }  // namespace extensions |