Home | History | Annotate | Download | only in declarative_webrequest
      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.
      4 
      5 #include "extensions/browser/api/declarative_webrequest/webrequest_action.h"
      6 
      7 #include <limits>
      8 
      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"
     31 
     32 using content::ResourceRequestInfo;
     33 
     34 namespace extensions {
     35 
     36 namespace helpers = extension_web_request_api_helpers;
     37 namespace keys = declarative_webrequest_constants;
     38 
     39 namespace {
     40 // Error messages.
     41 const char kIgnoreRulesRequiresParameterError[] =
     42     "IgnoreRules requires at least one parameter.";
     43 
     44 const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh"
     45     "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==";
     46 const char kEmptyDocumentUrl[] = "data:text/html,";
     47 
     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)
     54 
     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();
     64 }
     65 
     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));
     87 }
     88 
     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();
     94 }
     95 
     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());
    101 
    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();
    111 }
    112 
    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);
    122 }
    123 
    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));
    137 }
    138 
    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));
    150 
    151   to = WebRequestRedirectByRegExAction::PerlToRe2Style(to);
    152 
    153   RE2::Options options;
    154   options.set_case_sensitive(false);
    155   scoped_ptr<RE2> from_pattern(new RE2(from, options));
    156 
    157   if (!from_pattern->ok()) {
    158     *error = "Invalid pattern '" + from + "' -> '" + to + "'";
    159     return scoped_refptr<const WebRequestAction>(NULL);
    160   }
    161   return scoped_refptr<const WebRequestAction>(
    162       new WebRequestRedirectByRegExAction(from_pattern.Pass(), to));
    163 }
    164 
    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);
    179   }
    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);
    184   }
    185   return scoped_refptr<const WebRequestAction>(
    186       new WebRequestSetRequestHeaderAction(name, value));
    187 }
    188 
    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);
    201   }
    202   return scoped_refptr<const WebRequestAction>(
    203       new WebRequestRemoveRequestHeaderAction(name));
    204 }
    205 
    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);
    220   }
    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);
    225   }
    226   return scoped_refptr<const WebRequestAction>(
    227       new WebRequestAddResponseHeaderAction(name, value));
    228 }
    229 
    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);
    244   }
    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);
    249   }
    250   return scoped_refptr<const WebRequestAction>(
    251       new WebRequestRemoveResponseHeaderAction(name, value, has_value));
    252 }
    253 
    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;
    268   }
    269   if (dict->HasKey(keys::kHasTagKey)) {
    270     INPUT_FORMAT_VALIDATE(dict->GetString(keys::kHasTagKey, &ignore_tag));
    271     has_parameter = true;
    272   }
    273   if (!has_parameter) {
    274     *error = kIgnoreRulesRequiresParameterError;
    275     return scoped_refptr<const WebRequestAction>(NULL);
    276   }
    277   return scoped_refptr<const WebRequestAction>(
    278       new WebRequestIgnoreRulesAction(minimum_priority, ignore_tag));
    279 }
    280 
    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;
    287 
    288   const base::DictionaryValue* dict = NULL;
    289   CHECK(value->GetAsDictionary(&dict));
    290 
    291   linked_ptr<RequestCookieModification> modification(
    292       new RequestCookieModification);
    293 
    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);
    303 
    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);
    310   }
    311 
    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);
    321   }
    322 
    323   return scoped_refptr<const WebRequestAction>(
    324       new WebRequestRequestCookieAction(modification));
    325 }
    326 
    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;
    333 
    334   const base::DictionaryValue* dict = NULL;
    335   CHECK(value->GetAsDictionary(&dict));
    336 
    337   linked_ptr<ResponseCookieModification> modification(
    338       new ResponseCookieModification);
    339 
    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);
    349 
    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);
    356   }
    357 
    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);
    367   }
    368 
    369   return scoped_refptr<const WebRequestAction>(
    370       new WebRequestResponseCookieAction(modification));
    371 }
    372 
    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));
    384 }
    385 
    386 struct WebRequestActionFactory {
    387   DedupingFactory<WebRequestAction> factory;
    388 
    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);
    459   }
    460 };
    461 
    462 base::LazyInstance<WebRequestActionFactory>::Leaky
    463     g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER;
    464 
    465 }  // namespace
    466 
    467 //
    468 // WebRequestAction
    469 //
    470 
    471 WebRequestAction::~WebRequestAction() {}
    472 
    473 bool WebRequestAction::Equals(const WebRequestAction* other) const {
    474   return type() == other->type();
    475 }
    476 
    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;
    483 
    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;
    488 
    489   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
    490   int process_id = info ? info->GetChildID() : 0;
    491 
    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;
    496 
    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;
    508   }
    509   return WebRequestPermissions::CanExtensionAccessURL(
    510       extension_info_map, extension_id, request->url(), crosses_incognito,
    511       permission_check);
    512 }
    513 
    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;
    523 
    524   const base::DictionaryValue* action_dict = NULL;
    525   INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
    526 
    527   std::string instance_type;
    528   INPUT_FORMAT_VALIDATE(
    529       action_dict->GetString(keys::kInstanceTypeKey, &instance_type));
    530 
    531   WebRequestActionFactory& factory = g_web_request_action_factory.Get();
    532   return factory.factory.Instantiate(
    533       instance_type, action_dict, error, bad_message);
    534 }
    535 
    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());
    553     }
    554   }
    555 }
    556 
    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) {}
    565 
    566 //
    567 // WebRequestCancelAction
    568 //
    569 
    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) {}
    576 
    577 WebRequestCancelAction::~WebRequestCancelAction() {}
    578 
    579 std::string WebRequestCancelAction::GetName() const {
    580   return keys::kCancelRequestType;
    581 }
    582 
    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;
    592 }
    593 
    594 //
    595 // WebRequestRedirectAction
    596 //
    597 
    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) {}
    604 
    605 WebRequestRedirectAction::~WebRequestRedirectAction() {}
    606 
    607 bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const {
    608   return WebRequestAction::Equals(other) &&
    609          redirect_url_ ==
    610              static_cast<const WebRequestRedirectAction*>(other)->redirect_url_;
    611 }
    612 
    613 std::string WebRequestRedirectAction::GetName() const {
    614   return keys::kRedirectRequestType;
    615 }
    616 
    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;
    628 }
    629 
    630 //
    631 // WebRequestRedirectToTransparentImageAction
    632 //
    633 
    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) {}
    640 
    641 WebRequestRedirectToTransparentImageAction::
    642 ~WebRequestRedirectToTransparentImageAction() {}
    643 
    644 std::string WebRequestRedirectToTransparentImageAction::GetName() const {
    645   return keys::kRedirectToTransparentImageType;
    646 }
    647 
    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;
    658 }
    659 
    660 //
    661 // WebRequestRedirectToEmptyDocumentAction
    662 //
    663 
    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) {}
    670 
    671 WebRequestRedirectToEmptyDocumentAction::
    672 ~WebRequestRedirectToEmptyDocumentAction() {}
    673 
    674 std::string WebRequestRedirectToEmptyDocumentAction::GetName() const {
    675   return keys::kRedirectToEmptyDocumentType;
    676 }
    677 
    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;
    688 }
    689 
    690 //
    691 // WebRequestRedirectByRegExAction
    692 //
    693 
    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()) {}
    703 
    704 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
    705 
    706 // About the syntax of the two languages:
    707 //
    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.
    716 //
    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.
    721 
    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;
    739       }
    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;
    750       }
    751     } else {
    752       result += *i;
    753     }
    754     ++i;
    755   }
    756   return result;
    757 }
    758 
    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_;
    767 }
    768 
    769 std::string WebRequestRedirectByRegExAction::GetName() const {
    770   return keys::kRedirectByRegExType;
    771 }
    772 
    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());
    779 
    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);
    785   }
    786 
    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;
    792 }
    793 
    794 //
    795 // WebRequestSetRequestHeaderAction
    796 //
    797 
    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) {}
    807 
    808 WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {}
    809 
    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_;
    817 }
    818 
    819 std::string WebRequestSetRequestHeaderAction::GetName() const {
    820   return keys::kSetRequestHeaderType;
    821 }
    822 
    823 
    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;
    834 }
    835 
    836 //
    837 // WebRequestRemoveRequestHeaderAction
    838 //
    839 
    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) {}
    847 
    848 WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {}
    849 
    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_;
    857 }
    858 
    859 std::string WebRequestRemoveRequestHeaderAction::GetName() const {
    860   return keys::kRemoveRequestHeaderType;
    861 }
    862 
    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;
    873 }
    874 
    875 //
    876 // WebRequestAddResponseHeaderAction
    877 //
    878 
    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) {}
    888 
    889 WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {}
    890 
    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_;
    898 }
    899 
    900 std::string WebRequestAddResponseHeaderAction::GetName() const {
    901   return keys::kAddResponseHeaderType;
    902 }
    903 
    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);
    914 
    915   // Don't generate the header if it exists already.
    916   if (headers->HasHeaderValue(name_, value_))
    917     return LinkedPtrEventResponseDelta(NULL);
    918 
    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;
    923 }
    924 
    925 //
    926 // WebRequestRemoveResponseHeaderAction
    927 //
    928 
    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) {}
    940 
    941 WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {}
    942 
    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_;
    951 }
    952 
    953 std::string WebRequestRemoveResponseHeaderAction::GetName() const {
    954   return keys::kRemoveResponseHeaderType;
    955 }
    956 
    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);
    967 
    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;
    979     }
    980     result->deleted_response_headers.push_back(make_pair(name_, current_value));
    981   }
    982   return result;
    983 }
    984 
    985 //
    986 // WebRequestIgnoreRulesAction
    987 //
    988 
    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) {}
    998 
    999 WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {}
   1000 
   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_;
   1008 }
   1009 
   1010 std::string WebRequestIgnoreRulesAction::GetName() const {
   1011   return keys::kIgnoreRulesType;
   1012 }
   1013 
   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);
   1020 }
   1021 
   1022 //
   1023 // WebRequestRequestCookieAction
   1024 //
   1025 
   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());
   1034 }
   1035 
   1036 WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
   1037 
   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());
   1047 }
   1048 
   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;
   1057   }
   1058   NOTREACHED();
   1059   return "";
   1060 }
   1061 
   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;
   1073 }
   1074 
   1075 //
   1076 // WebRequestResponseCookieAction
   1077 //
   1078 
   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());
   1087 }
   1088 
   1089 WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
   1090 
   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());
   1100 }
   1101 
   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;
   1110   }
   1111   NOTREACHED();
   1112   return "";
   1113 }
   1114 
   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;
   1126 }
   1127 
   1128 //
   1129 // WebRequestSendMessageToExtensionAction
   1130 //
   1131 
   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) {}
   1140 
   1141 WebRequestSendMessageToExtensionAction::
   1142 ~WebRequestSendMessageToExtensionAction() {}
   1143 
   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_;
   1151 }
   1152 
   1153 std::string WebRequestSendMessageToExtensionAction::GetName() const {
   1154   return keys::kSendMessageToExtensionType;
   1155 }
   1156 
   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;
   1167 }
   1168 
   1169 }  // namespace extensions
   1170