| 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_condit
ion_attribute.h" | 5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit
ion_attribute.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 ~WebRequestConditionAttributeResourceType() {} | 131 ~WebRequestConditionAttributeResourceType() {} |
| 132 | 132 |
| 133 // static | 133 // static |
| 134 scoped_refptr<const WebRequestConditionAttribute> | 134 scoped_refptr<const WebRequestConditionAttribute> |
| 135 WebRequestConditionAttributeResourceType::Create( | 135 WebRequestConditionAttributeResourceType::Create( |
| 136 const std::string& instance_type, | 136 const std::string& instance_type, |
| 137 const base::Value* value, | 137 const base::Value* value, |
| 138 std::string* error, | 138 std::string* error, |
| 139 bool* bad_message) { | 139 bool* bad_message) { |
| 140 DCHECK(instance_type == keys::kResourceTypeKey); | 140 DCHECK(instance_type == keys::kResourceTypeKey); |
| 141 const ListValue* value_as_list = NULL; | 141 const base::ListValue* value_as_list = NULL; |
| 142 if (!value->GetAsList(&value_as_list)) { | 142 if (!value->GetAsList(&value_as_list)) { |
| 143 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, | 143 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, |
| 144 keys::kResourceTypeKey); | 144 keys::kResourceTypeKey); |
| 145 return scoped_refptr<const WebRequestConditionAttribute>(NULL); | 145 return scoped_refptr<const WebRequestConditionAttribute>(NULL); |
| 146 } | 146 } |
| 147 | 147 |
| 148 size_t number_types = value_as_list->GetSize(); | 148 size_t number_types = value_as_list->GetSize(); |
| 149 | 149 |
| 150 std::vector<ResourceType::Type> passed_types; | 150 std::vector<ResourceType::Type> passed_types; |
| 151 passed_types.reserve(number_types); | 151 passed_types.reserve(number_types); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 | 217 |
| 218 // static | 218 // static |
| 219 scoped_refptr<const WebRequestConditionAttribute> | 219 scoped_refptr<const WebRequestConditionAttribute> |
| 220 WebRequestConditionAttributeContentType::Create( | 220 WebRequestConditionAttributeContentType::Create( |
| 221 const std::string& name, | 221 const std::string& name, |
| 222 const base::Value* value, | 222 const base::Value* value, |
| 223 std::string* error, | 223 std::string* error, |
| 224 bool* bad_message) { | 224 bool* bad_message) { |
| 225 DCHECK(name == keys::kContentTypeKey || name == keys::kExcludeContentTypeKey); | 225 DCHECK(name == keys::kContentTypeKey || name == keys::kExcludeContentTypeKey); |
| 226 | 226 |
| 227 const ListValue* value_as_list = NULL; | 227 const base::ListValue* value_as_list = NULL; |
| 228 if (!value->GetAsList(&value_as_list)) { | 228 if (!value->GetAsList(&value_as_list)) { |
| 229 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); | 229 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); |
| 230 return scoped_refptr<const WebRequestConditionAttribute>(NULL); | 230 return scoped_refptr<const WebRequestConditionAttribute>(NULL); |
| 231 } | 231 } |
| 232 std::vector<std::string> content_types; | 232 std::vector<std::string> content_types; |
| 233 for (ListValue::const_iterator it = value_as_list->begin(); | 233 for (base::ListValue::const_iterator it = value_as_list->begin(); |
| 234 it != value_as_list->end(); ++it) { | 234 it != value_as_list->end(); ++it) { |
| 235 std::string content_type; | 235 std::string content_type; |
| 236 if (!(*it)->GetAsString(&content_type)) { | 236 if (!(*it)->GetAsString(&content_type)) { |
| 237 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); | 237 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); |
| 238 return scoped_refptr<const WebRequestConditionAttribute>(NULL); | 238 return scoped_refptr<const WebRequestConditionAttribute>(NULL); |
| 239 } | 239 } |
| 240 content_types.push_back(content_type); | 240 content_types.push_back(content_type); |
| 241 } | 241 } |
| 242 | 242 |
| 243 return scoped_refptr<const WebRequestConditionAttribute>( | 243 return scoped_refptr<const WebRequestConditionAttribute>( |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 bool TestNameValue(const std::string& name, const std::string& value) const; | 307 bool TestNameValue(const std::string& name, const std::string& value) const; |
| 308 | 308 |
| 309 private: | 309 private: |
| 310 // Represents a single string-matching test. | 310 // Represents a single string-matching test. |
| 311 class StringMatchTest { | 311 class StringMatchTest { |
| 312 public: | 312 public: |
| 313 enum MatchType { kPrefix, kSuffix, kEquals, kContains }; | 313 enum MatchType { kPrefix, kSuffix, kEquals, kContains }; |
| 314 | 314 |
| 315 // |data| is the pattern to be matched in the position given by |type|. | 315 // |data| is the pattern to be matched in the position given by |type|. |
| 316 // Note that |data| must point to a StringValue object. | 316 // Note that |data| must point to a StringValue object. |
| 317 static scoped_ptr<StringMatchTest> Create(const Value* data, | 317 static scoped_ptr<StringMatchTest> Create(const base::Value* data, |
| 318 MatchType type, | 318 MatchType type, |
| 319 bool case_sensitive); | 319 bool case_sensitive); |
| 320 ~StringMatchTest(); | 320 ~StringMatchTest(); |
| 321 | 321 |
| 322 // Does |str| pass |this| StringMatchTest? | 322 // Does |str| pass |this| StringMatchTest? |
| 323 bool Matches(const std::string& str) const; | 323 bool Matches(const std::string& str) const; |
| 324 | 324 |
| 325 private: | 325 private: |
| 326 StringMatchTest(const std::string& data, | 326 StringMatchTest(const std::string& data, |
| 327 MatchType type, | 327 MatchType type, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 }; | 367 }; |
| 368 | 368 |
| 369 // HeaderMatcher implementation. | 369 // HeaderMatcher implementation. |
| 370 | 370 |
| 371 HeaderMatcher::~HeaderMatcher() {} | 371 HeaderMatcher::~HeaderMatcher() {} |
| 372 | 372 |
| 373 // static | 373 // static |
| 374 scoped_ptr<const HeaderMatcher> HeaderMatcher::Create( | 374 scoped_ptr<const HeaderMatcher> HeaderMatcher::Create( |
| 375 const base::ListValue* tests) { | 375 const base::ListValue* tests) { |
| 376 ScopedVector<const HeaderMatchTest> header_tests; | 376 ScopedVector<const HeaderMatchTest> header_tests; |
| 377 for (ListValue::const_iterator it = tests->begin(); | 377 for (base::ListValue::const_iterator it = tests->begin(); |
| 378 it != tests->end(); ++it) { | 378 it != tests->end(); ++it) { |
| 379 const DictionaryValue* tests = NULL; | 379 const base::DictionaryValue* tests = NULL; |
| 380 if (!(*it)->GetAsDictionary(&tests)) | 380 if (!(*it)->GetAsDictionary(&tests)) |
| 381 return scoped_ptr<const HeaderMatcher>(); | 381 return scoped_ptr<const HeaderMatcher>(); |
| 382 | 382 |
| 383 scoped_ptr<const HeaderMatchTest> header_test( | 383 scoped_ptr<const HeaderMatchTest> header_test( |
| 384 HeaderMatchTest::Create(tests)); | 384 HeaderMatchTest::Create(tests)); |
| 385 if (header_test.get() == NULL) | 385 if (header_test.get() == NULL) |
| 386 return scoped_ptr<const HeaderMatcher>(); | 386 return scoped_ptr<const HeaderMatcher>(); |
| 387 header_tests.push_back(header_test.release()); | 387 header_tests.push_back(header_test.release()); |
| 388 } | 388 } |
| 389 | 389 |
| 390 return scoped_ptr<const HeaderMatcher>(new HeaderMatcher(&header_tests)); | 390 return scoped_ptr<const HeaderMatcher>(new HeaderMatcher(&header_tests)); |
| 391 } | 391 } |
| 392 | 392 |
| 393 bool HeaderMatcher::TestNameValue(const std::string& name, | 393 bool HeaderMatcher::TestNameValue(const std::string& name, |
| 394 const std::string& value) const { | 394 const std::string& value) const { |
| 395 for (size_t i = 0; i < tests_.size(); ++i) { | 395 for (size_t i = 0; i < tests_.size(); ++i) { |
| 396 if (tests_[i]->Matches(name, value)) | 396 if (tests_[i]->Matches(name, value)) |
| 397 return true; | 397 return true; |
| 398 } | 398 } |
| 399 return false; | 399 return false; |
| 400 } | 400 } |
| 401 | 401 |
| 402 HeaderMatcher::HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests) | 402 HeaderMatcher::HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests) |
| 403 : tests_(tests->Pass()) {} | 403 : tests_(tests->Pass()) {} |
| 404 | 404 |
| 405 // HeaderMatcher::StringMatchTest implementation. | 405 // HeaderMatcher::StringMatchTest implementation. |
| 406 | 406 |
| 407 // static | 407 // static |
| 408 scoped_ptr<HeaderMatcher::StringMatchTest> | 408 scoped_ptr<HeaderMatcher::StringMatchTest> |
| 409 HeaderMatcher::StringMatchTest::Create(const Value* data, | 409 HeaderMatcher::StringMatchTest::Create(const base::Value* data, |
| 410 MatchType type, | 410 MatchType type, |
| 411 bool case_sensitive) { | 411 bool case_sensitive) { |
| 412 std::string str; | 412 std::string str; |
| 413 CHECK(data->GetAsString(&str)); | 413 CHECK(data->GetAsString(&str)); |
| 414 return scoped_ptr<StringMatchTest>( | 414 return scoped_ptr<StringMatchTest>( |
| 415 new StringMatchTest(str, type, case_sensitive)); | 415 new StringMatchTest(str, type, case_sensitive)); |
| 416 } | 416 } |
| 417 | 417 |
| 418 HeaderMatcher::StringMatchTest::~StringMatchTest() {} | 418 HeaderMatcher::StringMatchTest::~StringMatchTest() {} |
| 419 | 419 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 value_match_(value_match->Pass()) {} | 456 value_match_(value_match->Pass()) {} |
| 457 | 457 |
| 458 HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {} | 458 HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {} |
| 459 | 459 |
| 460 // static | 460 // static |
| 461 scoped_ptr<const HeaderMatcher::HeaderMatchTest> | 461 scoped_ptr<const HeaderMatcher::HeaderMatchTest> |
| 462 HeaderMatcher::HeaderMatchTest::Create(const base::DictionaryValue* tests) { | 462 HeaderMatcher::HeaderMatchTest::Create(const base::DictionaryValue* tests) { |
| 463 ScopedVector<const StringMatchTest> name_match; | 463 ScopedVector<const StringMatchTest> name_match; |
| 464 ScopedVector<const StringMatchTest> value_match; | 464 ScopedVector<const StringMatchTest> value_match; |
| 465 | 465 |
| 466 for (DictionaryValue::Iterator it(*tests); !it.IsAtEnd(); it.Advance()) { | 466 for (base::DictionaryValue::Iterator it(*tests); |
| 467 !it.IsAtEnd(); it.Advance()) { |
| 467 bool is_name = false; // Is this test for header name? | 468 bool is_name = false; // Is this test for header name? |
| 468 StringMatchTest::MatchType match_type; | 469 StringMatchTest::MatchType match_type; |
| 469 if (it.key() == keys::kNamePrefixKey) { | 470 if (it.key() == keys::kNamePrefixKey) { |
| 470 is_name = true; | 471 is_name = true; |
| 471 match_type = StringMatchTest::kPrefix; | 472 match_type = StringMatchTest::kPrefix; |
| 472 } else if (it.key() == keys::kNameSuffixKey) { | 473 } else if (it.key() == keys::kNameSuffixKey) { |
| 473 is_name = true; | 474 is_name = true; |
| 474 match_type = StringMatchTest::kSuffix; | 475 match_type = StringMatchTest::kSuffix; |
| 475 } else if (it.key() == keys::kNameContainsKey) { | 476 } else if (it.key() == keys::kNameContainsKey) { |
| 476 is_name = true; | 477 is_name = true; |
| 477 match_type = StringMatchTest::kContains; | 478 match_type = StringMatchTest::kContains; |
| 478 } else if (it.key() == keys::kNameEqualsKey) { | 479 } else if (it.key() == keys::kNameEqualsKey) { |
| 479 is_name = true; | 480 is_name = true; |
| 480 match_type = StringMatchTest::kEquals; | 481 match_type = StringMatchTest::kEquals; |
| 481 } else if (it.key() == keys::kValuePrefixKey) { | 482 } else if (it.key() == keys::kValuePrefixKey) { |
| 482 match_type = StringMatchTest::kPrefix; | 483 match_type = StringMatchTest::kPrefix; |
| 483 } else if (it.key() == keys::kValueSuffixKey) { | 484 } else if (it.key() == keys::kValueSuffixKey) { |
| 484 match_type = StringMatchTest::kSuffix; | 485 match_type = StringMatchTest::kSuffix; |
| 485 } else if (it.key() == keys::kValueContainsKey) { | 486 } else if (it.key() == keys::kValueContainsKey) { |
| 486 match_type = StringMatchTest::kContains; | 487 match_type = StringMatchTest::kContains; |
| 487 } else if (it.key() == keys::kValueEqualsKey) { | 488 } else if (it.key() == keys::kValueEqualsKey) { |
| 488 match_type = StringMatchTest::kEquals; | 489 match_type = StringMatchTest::kEquals; |
| 489 } else { | 490 } else { |
| 490 NOTREACHED(); // JSON schema type checking should prevent this. | 491 NOTREACHED(); // JSON schema type checking should prevent this. |
| 491 return scoped_ptr<const HeaderMatchTest>(); | 492 return scoped_ptr<const HeaderMatchTest>(); |
| 492 } | 493 } |
| 493 const Value* content = &it.value(); | 494 const base::Value* content = &it.value(); |
| 494 | 495 |
| 495 ScopedVector<const StringMatchTest>* tests = | 496 ScopedVector<const StringMatchTest>* tests = |
| 496 is_name ? &name_match : &value_match; | 497 is_name ? &name_match : &value_match; |
| 497 switch (content->GetType()) { | 498 switch (content->GetType()) { |
| 498 case Value::TYPE_LIST: { | 499 case base::Value::TYPE_LIST: { |
| 499 const ListValue* list = NULL; | 500 const base::ListValue* list = NULL; |
| 500 CHECK(content->GetAsList(&list)); | 501 CHECK(content->GetAsList(&list)); |
| 501 for (ListValue::const_iterator it = list->begin(); | 502 for (base::ListValue::const_iterator it = list->begin(); |
| 502 it != list->end(); ++it) { | 503 it != list->end(); ++it) { |
| 503 tests->push_back( | 504 tests->push_back( |
| 504 StringMatchTest::Create(*it, match_type, !is_name).release()); | 505 StringMatchTest::Create(*it, match_type, !is_name).release()); |
| 505 } | 506 } |
| 506 break; | 507 break; |
| 507 } | 508 } |
| 508 case Value::TYPE_STRING: { | 509 case base::Value::TYPE_STRING: { |
| 509 tests->push_back( | 510 tests->push_back( |
| 510 StringMatchTest::Create(content, match_type, !is_name).release()); | 511 StringMatchTest::Create(content, match_type, !is_name).release()); |
| 511 break; | 512 break; |
| 512 } | 513 } |
| 513 default: { | 514 default: { |
| 514 NOTREACHED(); // JSON schema type checking should prevent this. | 515 NOTREACHED(); // JSON schema type checking should prevent this. |
| 515 return scoped_ptr<const HeaderMatchTest>(); | 516 return scoped_ptr<const HeaderMatchTest>(); |
| 516 } | 517 } |
| 517 } | 518 } |
| 518 } | 519 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 549 | 550 |
| 550 WebRequestConditionAttributeRequestHeaders:: | 551 WebRequestConditionAttributeRequestHeaders:: |
| 551 ~WebRequestConditionAttributeRequestHeaders() {} | 552 ~WebRequestConditionAttributeRequestHeaders() {} |
| 552 | 553 |
| 553 namespace { | 554 namespace { |
| 554 | 555 |
| 555 scoped_ptr<const HeaderMatcher> PrepareHeaderMatcher( | 556 scoped_ptr<const HeaderMatcher> PrepareHeaderMatcher( |
| 556 const std::string& name, | 557 const std::string& name, |
| 557 const base::Value* value, | 558 const base::Value* value, |
| 558 std::string* error) { | 559 std::string* error) { |
| 559 const ListValue* value_as_list = NULL; | 560 const base::ListValue* value_as_list = NULL; |
| 560 if (!value->GetAsList(&value_as_list)) { | 561 if (!value->GetAsList(&value_as_list)) { |
| 561 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); | 562 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); |
| 562 return scoped_ptr<const HeaderMatcher>(); | 563 return scoped_ptr<const HeaderMatcher>(); |
| 563 } | 564 } |
| 564 | 565 |
| 565 scoped_ptr<const HeaderMatcher> header_matcher( | 566 scoped_ptr<const HeaderMatcher> header_matcher( |
| 566 HeaderMatcher::Create(value_as_list)); | 567 HeaderMatcher::Create(value_as_list)); |
| 567 if (header_matcher.get() == NULL) | 568 if (header_matcher.get() == NULL) |
| 568 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); | 569 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, name); |
| 569 return header_matcher.Pass(); | 570 return header_matcher.Pass(); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 : allowed_stages_(allowed_stages) {} | 789 : allowed_stages_(allowed_stages) {} |
| 789 | 790 |
| 790 WebRequestConditionAttributeStages:: | 791 WebRequestConditionAttributeStages:: |
| 791 ~WebRequestConditionAttributeStages() {} | 792 ~WebRequestConditionAttributeStages() {} |
| 792 | 793 |
| 793 namespace { | 794 namespace { |
| 794 | 795 |
| 795 // Reads strings stored in |value|, which is expected to be a ListValue, and | 796 // Reads strings stored in |value|, which is expected to be a ListValue, and |
| 796 // sets corresponding bits (see RequestStage) in |out_stages|. Returns true on | 797 // sets corresponding bits (see RequestStage) in |out_stages|. Returns true on |
| 797 // success, false otherwise. | 798 // success, false otherwise. |
| 798 bool ParseListOfStages(const Value& value, int* out_stages) { | 799 bool ParseListOfStages(const base::Value& value, int* out_stages) { |
| 799 const ListValue* list = NULL; | 800 const base::ListValue* list = NULL; |
| 800 if (!value.GetAsList(&list)) | 801 if (!value.GetAsList(&list)) |
| 801 return false; | 802 return false; |
| 802 | 803 |
| 803 int stages = 0; | 804 int stages = 0; |
| 804 std::string stage_name; | 805 std::string stage_name; |
| 805 for (ListValue::const_iterator it = list->begin(); it != list->end(); ++it) { | 806 for (base::ListValue::const_iterator it = list->begin(); |
| 807 it != list->end(); ++it) { |
| 806 if (!((*it)->GetAsString(&stage_name))) | 808 if (!((*it)->GetAsString(&stage_name))) |
| 807 return false; | 809 return false; |
| 808 if (stage_name == keys::kOnBeforeRequestEnum) { | 810 if (stage_name == keys::kOnBeforeRequestEnum) { |
| 809 stages |= ON_BEFORE_REQUEST; | 811 stages |= ON_BEFORE_REQUEST; |
| 810 } else if (stage_name == keys::kOnBeforeSendHeadersEnum) { | 812 } else if (stage_name == keys::kOnBeforeSendHeadersEnum) { |
| 811 stages |= ON_BEFORE_SEND_HEADERS; | 813 stages |= ON_BEFORE_SEND_HEADERS; |
| 812 } else if (stage_name == keys::kOnHeadersReceivedEnum) { | 814 } else if (stage_name == keys::kOnHeadersReceivedEnum) { |
| 813 stages |= ON_HEADERS_RECEIVED; | 815 stages |= ON_HEADERS_RECEIVED; |
| 814 } else if (stage_name == keys::kOnAuthRequiredEnum) { | 816 } else if (stage_name == keys::kOnAuthRequiredEnum) { |
| 815 stages |= ON_AUTH_REQUIRED; | 817 stages |= ON_AUTH_REQUIRED; |
| 816 } else { | 818 } else { |
| 817 NOTREACHED(); // JSON schema checks prevent getting here. | 819 NOTREACHED(); // JSON schema checks prevent getting here. |
| 818 return false; | 820 return false; |
| 819 } | 821 } |
| 820 } | 822 } |
| 821 | 823 |
| 822 *out_stages = stages; | 824 *out_stages = stages; |
| 823 return true; | 825 return true; |
| 824 } | 826 } |
| 825 | 827 |
| 826 } // namespace | 828 } // namespace |
| 827 | 829 |
| 828 // static | 830 // static |
| 829 scoped_refptr<const WebRequestConditionAttribute> | 831 scoped_refptr<const WebRequestConditionAttribute> |
| 830 WebRequestConditionAttributeStages::Create(const std::string& name, | 832 WebRequestConditionAttributeStages::Create(const std::string& name, |
| 831 const Value* value, | 833 const base::Value* value, |
| 832 std::string* error, | 834 std::string* error, |
| 833 bool* bad_message) { | 835 bool* bad_message) { |
| 834 DCHECK(name == keys::kStagesKey); | 836 DCHECK(name == keys::kStagesKey); |
| 835 | 837 |
| 836 int allowed_stages = 0; | 838 int allowed_stages = 0; |
| 837 if (!ParseListOfStages(*value, &allowed_stages)) { | 839 if (!ParseListOfStages(*value, &allowed_stages)) { |
| 838 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, | 840 *error = ErrorUtils::FormatErrorMessage(kInvalidValue, |
| 839 keys::kStagesKey); | 841 keys::kStagesKey); |
| 840 return scoped_refptr<const WebRequestConditionAttribute>(NULL); | 842 return scoped_refptr<const WebRequestConditionAttribute>(NULL); |
| 841 } | 843 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 866 bool WebRequestConditionAttributeStages::Equals( | 868 bool WebRequestConditionAttributeStages::Equals( |
| 867 const WebRequestConditionAttribute* other) const { | 869 const WebRequestConditionAttribute* other) const { |
| 868 if (!WebRequestConditionAttribute::Equals(other)) | 870 if (!WebRequestConditionAttribute::Equals(other)) |
| 869 return false; | 871 return false; |
| 870 const WebRequestConditionAttributeStages* casted_other = | 872 const WebRequestConditionAttributeStages* casted_other = |
| 871 static_cast<const WebRequestConditionAttributeStages*>(other); | 873 static_cast<const WebRequestConditionAttributeStages*>(other); |
| 872 return allowed_stages_ == casted_other->allowed_stages_; | 874 return allowed_stages_ == casted_other->allowed_stages_; |
| 873 } | 875 } |
| 874 | 876 |
| 875 } // namespace extensions | 877 } // namespace extensions |
| OLD | NEW |