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 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 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 516 scoped_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 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_, ¤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 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