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