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/extensions/extension_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 31using content::ResourceRequestInfo; 32 33namespace extensions { 34 35namespace helpers = extension_web_request_api_helpers; 36namespace keys = declarative_webrequest_constants; 37 38namespace { 39// Error messages. 40const char kIgnoreRulesRequiresParameterError[] = 41 "IgnoreRules requires at least one parameter."; 42 43const char kTransparentImageUrl[] = "data:image/png;base64,iVBORw0KGgoAAAANSUh" 44 "EUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="; 45const 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 54scoped_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 65void 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 88scoped_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 95scoped_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. 114template <class T> 115scoped_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 123scoped_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 138scoped_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 164scoped_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 188scoped_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 205scoped_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 229scoped_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 253scoped_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 280scoped_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 326scoped_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 372scoped_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 385struct 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 461base::LazyInstance<WebRequestActionFactory>::Leaky 462 g_web_request_action_factory = LAZY_INSTANCE_INITIALIZER; 463 464} // namespace 465 466// 467// WebRequestAction 468// 469 470WebRequestAction::~WebRequestAction() {} 471 472bool WebRequestAction::Equals(const WebRequestAction* other) const { 473 return type() == other->type(); 474} 475 476bool 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 int route_id = info ? info->GetRouteID() : 0; 491 ExtensionRendererState::WebViewInfo webview_info; 492 // The embedder can always access all hosts from within a <webview>. 493 // The same is not true of extensions. 494 if (ExtensionRendererState::GetInstance()->GetWebViewInfo( 495 process_id, route_id, &webview_info)) { 496 return true; 497 } 498 WebRequestPermissions::HostPermissionsCheck permission_check = 499 WebRequestPermissions::REQUIRE_ALL_URLS; 500 switch (host_permissions_strategy()) { 501 case STRATEGY_DEFAULT: // Default value is already set. 502 break; 503 case STRATEGY_NONE: 504 permission_check = WebRequestPermissions::DO_NOT_CHECK_HOST; 505 break; 506 case STRATEGY_HOST: 507 permission_check = WebRequestPermissions::REQUIRE_HOST_PERMISSION; 508 break; 509 } 510 return WebRequestPermissions::CanExtensionAccessURL( 511 extension_info_map, extension_id, request->url(), crosses_incognito, 512 permission_check); 513} 514 515// static 516scoped_refptr<const WebRequestAction> WebRequestAction::Create( 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 536void 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 557WebRequestAction::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 570WebRequestCancelAction::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 577WebRequestCancelAction::~WebRequestCancelAction() {} 578 579std::string WebRequestCancelAction::GetName() const { 580 return keys::kCancelRequestType; 581} 582 583LinkedPtrEventResponseDelta 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 598WebRequestRedirectAction::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 605WebRequestRedirectAction::~WebRequestRedirectAction() {} 606 607bool WebRequestRedirectAction::Equals(const WebRequestAction* other) const { 608 return WebRequestAction::Equals(other) && 609 redirect_url_ == 610 static_cast<const WebRequestRedirectAction*>(other)->redirect_url_; 611} 612 613std::string WebRequestRedirectAction::GetName() const { 614 return keys::kRedirectRequestType; 615} 616 617LinkedPtrEventResponseDelta 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 634WebRequestRedirectToTransparentImageAction:: 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 641WebRequestRedirectToTransparentImageAction:: 642~WebRequestRedirectToTransparentImageAction() {} 643 644std::string WebRequestRedirectToTransparentImageAction::GetName() const { 645 return keys::kRedirectToTransparentImageType; 646} 647 648LinkedPtrEventResponseDelta 649WebRequestRedirectToTransparentImageAction::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 664WebRequestRedirectToEmptyDocumentAction:: 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 671WebRequestRedirectToEmptyDocumentAction:: 672~WebRequestRedirectToEmptyDocumentAction() {} 673 674std::string WebRequestRedirectToEmptyDocumentAction::GetName() const { 675 return keys::kRedirectToEmptyDocumentType; 676} 677 678LinkedPtrEventResponseDelta 679WebRequestRedirectToEmptyDocumentAction::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 694WebRequestRedirectByRegExAction::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 704WebRequestRedirectByRegExAction::~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 723std::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 759bool 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 769std::string WebRequestRedirectByRegExAction::GetName() const { 770 return keys::kRedirectByRegExType; 771} 772 773LinkedPtrEventResponseDelta 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 798WebRequestSetRequestHeaderAction::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 808WebRequestSetRequestHeaderAction::~WebRequestSetRequestHeaderAction() {} 809 810bool 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 819std::string WebRequestSetRequestHeaderAction::GetName() const { 820 return keys::kSetRequestHeaderType; 821} 822 823 824LinkedPtrEventResponseDelta 825WebRequestSetRequestHeaderAction::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 840WebRequestRemoveRequestHeaderAction::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 848WebRequestRemoveRequestHeaderAction::~WebRequestRemoveRequestHeaderAction() {} 849 850bool 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 859std::string WebRequestRemoveRequestHeaderAction::GetName() const { 860 return keys::kRemoveRequestHeaderType; 861} 862 863LinkedPtrEventResponseDelta 864WebRequestRemoveRequestHeaderAction::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 879WebRequestAddResponseHeaderAction::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 889WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {} 890 891bool 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 900std::string WebRequestAddResponseHeaderAction::GetName() const { 901 return keys::kAddResponseHeaderType; 902} 903 904LinkedPtrEventResponseDelta 905WebRequestAddResponseHeaderAction::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 929WebRequestRemoveResponseHeaderAction::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 941WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {} 942 943bool 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 953std::string WebRequestRemoveResponseHeaderAction::GetName() const { 954 return keys::kRemoveResponseHeaderType; 955} 956 957LinkedPtrEventResponseDelta 958WebRequestRemoveResponseHeaderAction::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_, ¤t_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 989WebRequestIgnoreRulesAction::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 999WebRequestIgnoreRulesAction::~WebRequestIgnoreRulesAction() {} 1000 1001bool 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 1010std::string WebRequestIgnoreRulesAction::GetName() const { 1011 return keys::kIgnoreRulesType; 1012} 1013 1014LinkedPtrEventResponseDelta 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 1026WebRequestRequestCookieAction::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 1036WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {} 1037 1038bool 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 1049std::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 1062LinkedPtrEventResponseDelta 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 1079WebRequestResponseCookieAction::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 1089WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {} 1090 1091bool 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 1102std::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 1115LinkedPtrEventResponseDelta 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 1132WebRequestSendMessageToExtensionAction::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 1141WebRequestSendMessageToExtensionAction:: 1142~WebRequestSendMessageToExtensionAction() {} 1143 1144bool 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 1153std::string WebRequestSendMessageToExtensionAction::GetName() const { 1154 return keys::kSendMessageToExtensionType; 1155} 1156 1157LinkedPtrEventResponseDelta 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