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