Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action .h" | 5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action .h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | |
| 13 #include "base/values.h" | 14 #include "base/values.h" |
| 14 #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" | 15 #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" |
| 15 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_consta nts.h" | 16 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_consta nts.h" |
| 16 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" | 17 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" |
| 17 #include "net/url_request/url_request.h" | 18 #include "net/url_request/url_request.h" |
| 18 | 19 |
| 19 namespace extensions { | 20 namespace extensions { |
| 20 | 21 |
| 21 namespace keys = declarative_webrequest_constants; | 22 namespace keys = declarative_webrequest_constants; |
| 22 | 23 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 51 std::string* error, | 52 std::string* error, |
| 52 bool* bad_message) { | 53 bool* bad_message) { |
| 53 std::string redirect_url_string; | 54 std::string redirect_url_string; |
| 54 INPUT_FORMAT_VALIDATE( | 55 INPUT_FORMAT_VALIDATE( |
| 55 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string)); | 56 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string)); |
| 56 GURL redirect_url(redirect_url_string); | 57 GURL redirect_url(redirect_url_string); |
| 57 return scoped_ptr<WebRequestAction>( | 58 return scoped_ptr<WebRequestAction>( |
| 58 new WebRequestRedirectAction(redirect_url)); | 59 new WebRequestRedirectAction(redirect_url)); |
| 59 } | 60 } |
| 60 | 61 |
| 62 scoped_ptr<WebRequestAction> CreateRedirectRequestByRegExAction( | |
| 63 const base::DictionaryValue* dict, | |
| 64 std::string* error, | |
| 65 bool* bad_message) { | |
| 66 std::string from; | |
| 67 std::string to; | |
| 68 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from)); | |
| 69 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to)); | |
| 70 | |
| 71 // TODO(battre): Add this line once we migrate from ICU RegEx to RE2 RegEx.s | |
| 72 // to = WebRequestRedirectByRegExAction::PerlToRe2Style(to); | |
| 73 | |
| 74 UParseError parse_error; | |
| 75 UErrorCode status = U_ZERO_ERROR; | |
| 76 scoped_ptr<icu::RegexPattern> pattern( | |
| 77 icu::RegexPattern::compile(icu::UnicodeString(from.data(), from.size()), | |
| 78 0, parse_error, status)); | |
| 79 if (U_FAILURE(status) || !pattern.get()) { | |
| 80 *error = "Invalid pattern '" + from + "' -> '" + to + "'"; | |
| 81 return scoped_ptr<WebRequestAction>(NULL); | |
| 82 } | |
| 83 return scoped_ptr<WebRequestAction>( | |
| 84 new WebRequestRedirectByRegExAction(pattern.Pass(), to)); | |
| 85 } | |
| 86 | |
| 61 scoped_ptr<WebRequestAction> CreateSetRequestHeaderAction( | 87 scoped_ptr<WebRequestAction> CreateSetRequestHeaderAction( |
| 62 const base::DictionaryValue* dict, | 88 const base::DictionaryValue* dict, |
| 63 std::string* error, | 89 std::string* error, |
| 64 bool* bad_message) { | 90 bool* bad_message) { |
| 65 std::string name; | 91 std::string name; |
| 66 std::string value; | 92 std::string value; |
| 67 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); | 93 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); |
| 68 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value)); | 94 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value)); |
| 69 return scoped_ptr<WebRequestAction>( | 95 return scoped_ptr<WebRequestAction>( |
| 70 new WebRequestSetRequestHeaderAction(name, value)); | 96 new WebRequestSetRequestHeaderAction(name, value)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 125 (* FactoryMethod)(const base::DictionaryValue* /* dict */ , | 151 (* FactoryMethod)(const base::DictionaryValue* /* dict */ , |
| 126 std::string* /* error */, | 152 std::string* /* error */, |
| 127 bool* /* bad_message */); | 153 bool* /* bad_message */); |
| 128 std::map<std::string, FactoryMethod> factory_methods; | 154 std::map<std::string, FactoryMethod> factory_methods; |
| 129 | 155 |
| 130 WebRequestActionFactory() { | 156 WebRequestActionFactory() { |
| 131 factory_methods[keys::kAddResponseHeaderType] = | 157 factory_methods[keys::kAddResponseHeaderType] = |
| 132 &CreateAddResponseHeaderAction; | 158 &CreateAddResponseHeaderAction; |
| 133 factory_methods[keys::kCancelRequestType] = | 159 factory_methods[keys::kCancelRequestType] = |
| 134 &CallConstructorFactoryMethod<WebRequestCancelAction>; | 160 &CallConstructorFactoryMethod<WebRequestCancelAction>; |
| 161 factory_methods[keys::kRedirectByRegExType] = | |
| 162 &CreateRedirectRequestByRegExAction; | |
| 135 factory_methods[keys::kRedirectRequestType] = | 163 factory_methods[keys::kRedirectRequestType] = |
| 136 &CreateRedirectRequestAction; | 164 &CreateRedirectRequestAction; |
| 137 factory_methods[keys::kRedirectToTransparentImageType] = | 165 factory_methods[keys::kRedirectToTransparentImageType] = |
| 138 &CallConstructorFactoryMethod< | 166 &CallConstructorFactoryMethod< |
| 139 WebRequestRedirectToTransparentImageAction>; | 167 WebRequestRedirectToTransparentImageAction>; |
| 140 factory_methods[keys::kRedirectToEmptyDocumentType] = | 168 factory_methods[keys::kRedirectToEmptyDocumentType] = |
| 141 &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>; | 169 &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>; |
| 142 factory_methods[keys::kSetRequestHeaderType] = | 170 factory_methods[keys::kSetRequestHeaderType] = |
| 143 &CreateSetRequestHeaderAction; | 171 &CreateSetRequestHeaderAction; |
| 144 factory_methods[keys::kRemoveRequestHeaderType] = | 172 factory_methods[keys::kRemoveRequestHeaderType] = |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 const base::Time& extension_install_time) const { | 405 const base::Time& extension_install_time) const { |
| 378 CHECK(request_stage & GetStages()); | 406 CHECK(request_stage & GetStages()); |
| 379 LinkedPtrEventResponseDelta result( | 407 LinkedPtrEventResponseDelta result( |
| 380 new extension_web_request_api_helpers::EventResponseDelta( | 408 new extension_web_request_api_helpers::EventResponseDelta( |
| 381 extension_id, extension_install_time)); | 409 extension_id, extension_install_time)); |
| 382 result->new_url = GURL(kEmptyDocumentUrl); | 410 result->new_url = GURL(kEmptyDocumentUrl); |
| 383 return result; | 411 return result; |
| 384 } | 412 } |
| 385 | 413 |
| 386 // | 414 // |
| 415 // WebRequestRedirectByRegExAction | |
| 416 // | |
| 417 | |
| 418 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction( | |
| 419 scoped_ptr<icu::RegexPattern> from_pattern, | |
| 420 const std::string& to_pattern) | |
| 421 : from_pattern_(from_pattern.Pass()), | |
| 422 to_pattern_(to_pattern.data(), to_pattern.size()) {} | |
| 423 | |
| 424 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {} | |
| 425 | |
| 426 // About the syntax of the two languages: | |
| 427 // | |
| 428 // ICU (Perl) states: | |
| 429 // $n The text of capture group n will be substituted for $n. n must be >= 0 | |
| 430 // and not greater than the number of capture groups. A $ not followed by a | |
| 431 // digit has no special meaning, and will appear in the substitution text | |
| 432 // as itself, a $. | |
| 433 // \ Treat the following character as a literal, suppressing any special | |
| 434 // meaning. Backslash escaping in substitution text is only required for | |
| 435 // '$' and '\', but may be used on any other character without bad effects. | |
| 436 // | |
| 437 // RE2, derived from RE2::Rewrite() | |
| 438 // \ May only be followed by a digit or another \. If followed by a single | |
| 439 // digit, both characters represent the respective capture group. If followed | |
| 440 // by another \, it is used as an escape sequence. | |
| 441 | |
| 442 // static | |
| 443 std::string WebRequestRedirectByRegExAction::PerlToRe2Style( | |
| 444 const std::string& perl) { | |
| 445 std::string::const_iterator i = perl.begin(); | |
| 446 std::string result; | |
| 447 while (i != perl.end()) { | |
| 448 if (*i == '$') { | |
| 449 ++i; | |
| 450 if (i == perl.end()) { | |
| 451 result += '$'; | |
| 452 } else if (isdigit(*i)) { | |
| 453 result += '\\'; | |
| 454 result += *i; | |
| 455 } else { | |
| 456 result += '$'; | |
| 457 result += *i; | |
| 458 } | |
| 459 } else if (*i == '\\') { | |
| 460 ++i; | |
| 461 if (i == perl.end()) { | |
| 462 result += '\\'; | |
| 463 } else if (*i == '$'){ | |
|
Matt Perry
2012/06/14 18:39:13
nit: space before {
| |
| 464 result += '$'; | |
| 465 } else if (*i == '\\'){ | |
|
Matt Perry
2012/06/14 18:39:13
ditto
| |
| 466 result += "\\\\"; | |
| 467 } else { | |
| 468 result += *i; | |
| 469 } | |
| 470 } else { | |
| 471 result += *i; | |
| 472 } | |
| 473 ++i; | |
| 474 } | |
| 475 return result; | |
| 476 } | |
| 477 | |
| 478 int WebRequestRedirectByRegExAction::GetStages() const { | |
| 479 return ON_BEFORE_REQUEST; | |
| 480 } | |
| 481 | |
| 482 WebRequestAction::Type WebRequestRedirectByRegExAction::GetType() const { | |
| 483 return WebRequestAction::ACTION_REDIRECT_BY_REGEX_DOCUMENT; | |
| 484 } | |
| 485 | |
| 486 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta( | |
| 487 net::URLRequest* request, | |
| 488 RequestStages request_stage, | |
| 489 const WebRequestRule::OptionalRequestData& optional_request_data, | |
| 490 const std::string& extension_id, | |
| 491 const base::Time& extension_install_time) const { | |
| 492 CHECK(request_stage & GetStages()); | |
| 493 CHECK(from_pattern_.get()); | |
| 494 | |
| 495 UErrorCode status = U_ZERO_ERROR; | |
| 496 const std::string& old_url = request->url().spec(); | |
| 497 icu::UnicodeString old_url_unicode(old_url.data(), old_url.size()); | |
| 498 | |
| 499 scoped_ptr<icu::RegexMatcher> matcher( | |
| 500 from_pattern_->matcher(old_url_unicode, status)); | |
| 501 if (U_FAILURE(status) || !matcher.get()) | |
| 502 return LinkedPtrEventResponseDelta(NULL); | |
| 503 | |
| 504 icu::UnicodeString new_url = matcher->replaceAll(to_pattern_, status); | |
| 505 if (U_FAILURE(status)) | |
| 506 return LinkedPtrEventResponseDelta(NULL); | |
| 507 | |
| 508 std::string new_url_utf8; | |
| 509 UTF16ToUTF8(new_url.getBuffer(), new_url.length(), &new_url_utf8); | |
| 510 | |
| 511 if (new_url_utf8 == request->url().spec()) | |
| 512 return LinkedPtrEventResponseDelta(NULL); | |
| 513 | |
| 514 LinkedPtrEventResponseDelta result( | |
| 515 new extension_web_request_api_helpers::EventResponseDelta( | |
| 516 extension_id, extension_install_time)); | |
| 517 result->new_url = GURL(new_url_utf8); | |
| 518 return result; | |
| 519 } | |
| 520 | |
| 521 // | |
| 387 // WebRequestSetRequestHeaderAction | 522 // WebRequestSetRequestHeaderAction |
| 388 // | 523 // |
| 389 | 524 |
| 390 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction( | 525 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction( |
| 391 const std::string& name, | 526 const std::string& name, |
| 392 const std::string& value) | 527 const std::string& value) |
| 393 : name_(name), | 528 : name_(name), |
| 394 value_(value) { | 529 value_(value) { |
| 395 } | 530 } |
| 396 | 531 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 } | 613 } |
| 479 | 614 |
| 480 LinkedPtrEventResponseDelta | 615 LinkedPtrEventResponseDelta |
| 481 WebRequestAddResponseHeaderAction::CreateDelta( | 616 WebRequestAddResponseHeaderAction::CreateDelta( |
| 482 net::URLRequest* request, | 617 net::URLRequest* request, |
| 483 RequestStages request_stage, | 618 RequestStages request_stage, |
| 484 const WebRequestRule::OptionalRequestData& optional_request_data, | 619 const WebRequestRule::OptionalRequestData& optional_request_data, |
| 485 const std::string& extension_id, | 620 const std::string& extension_id, |
| 486 const base::Time& extension_install_time) const { | 621 const base::Time& extension_install_time) const { |
| 487 CHECK(request_stage & GetStages()); | 622 CHECK(request_stage & GetStages()); |
| 623 net::HttpResponseHeaders* headers = | |
| 624 optional_request_data.original_response_headers; | |
| 625 if (!headers) | |
| 626 return LinkedPtrEventResponseDelta(NULL); | |
| 627 | |
| 628 // Don't generate the header if it exists already. | |
| 629 if (headers->HasHeaderValue(name_, value_)) | |
| 630 return LinkedPtrEventResponseDelta(NULL); | |
| 631 | |
| 488 LinkedPtrEventResponseDelta result( | 632 LinkedPtrEventResponseDelta result( |
| 489 new extension_web_request_api_helpers::EventResponseDelta( | 633 new extension_web_request_api_helpers::EventResponseDelta( |
| 490 extension_id, extension_install_time)); | 634 extension_id, extension_install_time)); |
| 491 | |
| 492 net::HttpResponseHeaders* headers = | |
| 493 optional_request_data.original_response_headers; | |
| 494 if (!headers) | |
| 495 return result; | |
| 496 | |
| 497 // Don't generate the header if it exists already. | |
| 498 if (headers->HasHeaderValue(name_, value_)) | |
| 499 return result; | |
| 500 | |
| 501 result->added_response_headers.push_back(make_pair(name_, value_)); | 635 result->added_response_headers.push_back(make_pair(name_, value_)); |
| 502 return result; | 636 return result; |
| 503 } | 637 } |
| 504 | 638 |
| 505 // | 639 // |
| 506 // WebRequestRemoveResponseHeaderAction | 640 // WebRequestRemoveResponseHeaderAction |
| 507 // | 641 // |
| 508 | 642 |
| 509 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction( | 643 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction( |
| 510 const std::string& name, | 644 const std::string& name, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 527 } | 661 } |
| 528 | 662 |
| 529 LinkedPtrEventResponseDelta | 663 LinkedPtrEventResponseDelta |
| 530 WebRequestRemoveResponseHeaderAction::CreateDelta( | 664 WebRequestRemoveResponseHeaderAction::CreateDelta( |
| 531 net::URLRequest* request, | 665 net::URLRequest* request, |
| 532 RequestStages request_stage, | 666 RequestStages request_stage, |
| 533 const WebRequestRule::OptionalRequestData& optional_request_data, | 667 const WebRequestRule::OptionalRequestData& optional_request_data, |
| 534 const std::string& extension_id, | 668 const std::string& extension_id, |
| 535 const base::Time& extension_install_time) const { | 669 const base::Time& extension_install_time) const { |
| 536 CHECK(request_stage & GetStages()); | 670 CHECK(request_stage & GetStages()); |
| 671 net::HttpResponseHeaders* headers = | |
| 672 optional_request_data.original_response_headers; | |
| 673 if (!headers) | |
| 674 return LinkedPtrEventResponseDelta(NULL); | |
| 675 | |
| 537 LinkedPtrEventResponseDelta result( | 676 LinkedPtrEventResponseDelta result( |
| 538 new extension_web_request_api_helpers::EventResponseDelta( | 677 new extension_web_request_api_helpers::EventResponseDelta( |
| 539 extension_id, extension_install_time)); | 678 extension_id, extension_install_time)); |
| 540 net::HttpResponseHeaders* headers = | |
| 541 optional_request_data.original_response_headers; | |
| 542 if (!headers) | |
| 543 return result; | |
| 544 void* iter = NULL; | 679 void* iter = NULL; |
| 545 std::string current_value; | 680 std::string current_value; |
| 546 while (headers->EnumerateHeader(&iter, name_, ¤t_value)) { | 681 while (headers->EnumerateHeader(&iter, name_, ¤t_value)) { |
| 547 if (has_value_ && | 682 if (has_value_ && |
| 548 (current_value.size() != value_.size() || | 683 (current_value.size() != value_.size() || |
| 549 !std::equal(current_value.begin(), current_value.end(), | 684 !std::equal(current_value.begin(), current_value.end(), |
| 550 value_.begin(), | 685 value_.begin(), |
| 551 base::CaseInsensitiveCompare<char>()))) { | 686 base::CaseInsensitiveCompare<char>()))) { |
| 552 continue; | 687 continue; |
| 553 } | 688 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 584 net::URLRequest* request, | 719 net::URLRequest* request, |
| 585 RequestStages request_stage, | 720 RequestStages request_stage, |
| 586 const WebRequestRule::OptionalRequestData& optional_request_data, | 721 const WebRequestRule::OptionalRequestData& optional_request_data, |
| 587 const std::string& extension_id, | 722 const std::string& extension_id, |
| 588 const base::Time& extension_install_time) const { | 723 const base::Time& extension_install_time) const { |
| 589 CHECK(request_stage & GetStages()); | 724 CHECK(request_stage & GetStages()); |
| 590 return LinkedPtrEventResponseDelta(NULL); | 725 return LinkedPtrEventResponseDelta(NULL); |
| 591 } | 726 } |
| 592 | 727 |
| 593 } // namespace extensions | 728 } // namespace extensions |
| OLD | NEW |