Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc

Issue 10923002: Extracting header testing code from WebRequestConditionAttributeResponseHeaders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Corrected indenting, clarified comments and some names Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/logging.h" 9 #include "base/logging.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 return std::find(content_types_.begin(), content_types_.end(), 225 return std::find(content_types_.begin(), content_types_.end(),
226 mime_type) == content_types_.end(); 226 mime_type) == content_types_.end();
227 } 227 }
228 } 228 }
229 229
230 WebRequestConditionAttribute::Type 230 WebRequestConditionAttribute::Type
231 WebRequestConditionAttributeContentType::GetType() const { 231 WebRequestConditionAttributeContentType::GetType() const {
232 return CONDITION_CONTENT_TYPE; 232 return CONDITION_CONTENT_TYPE;
233 } 233 }
234 234
235 // 235 // Manages a set of tests to be applied to name-value pairs representing
236 // WebRequestConditionAttributeResponseHeaders 236 // headers. This is a helper class to header-related condition attributes.
237 // 237 // It contains a set of test groups. A name-value pair satisfies the whole
238 // set of test groups iff it passes at least one test group.
239 class HeaderMatcher {
240 public:
241 ~HeaderMatcher();
238 242
239 WebRequestConditionAttributeResponseHeaders::StringMatchTest::StringMatchTest( 243 // Creates an instance based on a list |tests| of test groups, encoded as
240 const std::string& data, 244 // dictionaries of the type declarativeWebRequest.HeaderFilter (see
241 MatchType type) 245 // declarative_web_request.json).
246 static scoped_ptr<const HeaderMatcher> Create(const base::ListValue* tests);
247
248 // Does |this| match the header "|name|: |value|"?
249 bool TestNameValue(const std::string& name, const std::string& value) const;
250
251 private:
252 // Represents a single string-matching test.
253 class StringMatchTest {
254 public:
255 enum MatchType { kPrefix, kSuffix, kEquals, kContains };
256
257 StringMatchTest(const std::string& data, MatchType type);
258 ~StringMatchTest();
259
260 // Takes a string to be matched, as a StringValue in |content|, an
261 // indication |is_name_test| of whether the test will be used for matching
262 // against header values or names, and a |match_type|. Never returns NULL,
263 // except for memory failures.
264 static scoped_ptr<const StringMatchTest> Create(const Value* content,
265 bool is_name_test,
266 MatchType match_type);
battre 2012/09/03 08:46:47 You can do this in a separate CL, but I think we c
vabr (Chromium) 2012/09/03 10:12:36 I thought about this before, but decided against i
battre 2012/09/03 12:48:08 My thoughts were from the perspective of somebody
vabr (Chromium) 2012/09/03 14:21:29 I agree with both points. StringToLowerASCII is no
267
268 // Does |str| pass |this| StringMatchTest?
269 bool Matches(const std::string& str) const;
270
271 private:
272 const std::string data_;
273 const MatchType type_;
274 DISALLOW_COPY_AND_ASSIGN(StringMatchTest);
275 };
276
277 // Represents a test group -- a set of string matching tests to be applied to
278 // both the header name and value.
279 class HeaderMatchTest {
280 public:
281 ~HeaderMatchTest();
282
283 // Gets the test group description in |tests| and creates the corresponding
284 // HeaderMatchTest. On failure returns NULL.
285 static scoped_ptr<const HeaderMatchTest> Create(
286 const base::DictionaryValue* tests);
287
288 // Does the header "|name|: |value|" match all tests in |this|?
289 bool Matches(const std::string& name, const std::string& value) const;
290
291 private:
292 // Takes ownership of the content of both |name_match| and |value_match|.
293 HeaderMatchTest(ScopedVector<const StringMatchTest>* name_match,
294 ScopedVector<const StringMatchTest>* value_match);
295
296 // Tests to be passed by a header's name.
297 const ScopedVector<const StringMatchTest> name_match_;
298 // Tests to be passed by a header's value.
299 const ScopedVector<const StringMatchTest> value_match_;
300 DISALLOW_COPY_AND_ASSIGN(HeaderMatchTest);
301 };
302
303 explicit HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests);
304
305 const ScopedVector<const HeaderMatchTest> tests_;
306
307 DISALLOW_COPY_AND_ASSIGN(HeaderMatcher);
308 };
309
310 // HeaderMatcher implementation.
311
312 HeaderMatcher::~HeaderMatcher() {}
313
314 // static
315 scoped_ptr<const HeaderMatcher> HeaderMatcher::Create(
316 const base::ListValue* tests) {
317 ScopedVector<const HeaderMatchTest> header_tests;
318 for (ListValue::const_iterator it = tests->begin();
319 it != tests->end(); ++it) {
320 const DictionaryValue* tests = NULL;
321 if (!(*it)->GetAsDictionary(&tests))
322 return scoped_ptr<const HeaderMatcher>(NULL);
323
324 scoped_ptr<const HeaderMatchTest> header_test(
325 HeaderMatchTest::Create(tests));
326 if (header_test.get() == NULL)
327 return scoped_ptr<const HeaderMatcher>(NULL);
328 header_tests.push_back(header_test.release());
329 }
330
331 return scoped_ptr<const HeaderMatcher>(
332 new HeaderMatcher(&header_tests));
battre 2012/09/03 08:46:47 nit: single line
vabr (Chromium) 2012/09/03 10:12:36 Done.
333 }
334
335 bool HeaderMatcher::TestNameValue(const std::string& name,
336 const std::string& value) const {
337 for (size_t i = 0; i < tests_.size(); ++i) {
338 if (tests_[i]->Matches(name, value))
339 return true;
340 }
341 return false;
342 }
343
344 HeaderMatcher::HeaderMatcher(ScopedVector<const HeaderMatchTest>* tests)
345 : tests_(tests->Pass()) {}
346
347 // HeaderMatcher::StringMatchTest implementation.
348
349 HeaderMatcher::StringMatchTest::StringMatchTest(const std::string& data,
350 MatchType type)
242 : data_(data), 351 : data_(data),
243 type_(type) {} 352 type_(type) {}
244 353
245 WebRequestConditionAttributeResponseHeaders::StringMatchTest::~StringMatchTest() 354 HeaderMatcher::StringMatchTest::~StringMatchTest() {}
246 {}
247
248 WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::HeaderMatchTest(
249 ScopedVector<const StringMatchTest>* name,
250 ScopedVector<const StringMatchTest>* value)
251 : name_(name->Pass()),
252 value_(value->Pass()) {}
253
254 WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::~HeaderMatchTest()
255 {}
256
257 WebRequestConditionAttributeResponseHeaders::
258 WebRequestConditionAttributeResponseHeaders(
259 bool positive_test, ScopedVector<const HeaderMatchTest>* tests)
260 : tests_(tests->Pass()),
261 positive_test_(positive_test) {}
262
263 WebRequestConditionAttributeResponseHeaders::
264 ~WebRequestConditionAttributeResponseHeaders() {}
265 355
266 // static 356 // static
267 bool WebRequestConditionAttributeResponseHeaders::IsMatchingType( 357 scoped_ptr<const HeaderMatcher::StringMatchTest>
268 const std::string& instance_type) { 358 HeaderMatcher::StringMatchTest::Create(const Value* content,
269 return instance_type == keys::kResponseHeadersKey || 359 bool is_name_test,
270 instance_type == keys::kExcludeResponseHeadersKey; 360 MatchType match_type) {
361 std::string str;
362
363 CHECK(content->GetAsString(&str));
364 // Header names are case-insensitive, we match them in lowercase.
365 if (is_name_test)
366 StringToLowerASCII(&str);
367
368 return scoped_ptr<const StringMatchTest>(
369 new StringMatchTest(str, match_type));
271 } 370 }
272 371
273 // static 372 bool HeaderMatcher::StringMatchTest::Matches(
274 scoped_ptr<WebRequestConditionAttribute>
275 WebRequestConditionAttributeResponseHeaders::Create(
276 const std::string& name,
277 const base::Value* value,
278 std::string* error) {
279 DCHECK(IsMatchingType(name));
280
281 const ListValue* value_as_list = NULL;
282 if (!value->GetAsList(&value_as_list)) {
283 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
284 return scoped_ptr<WebRequestConditionAttribute>(NULL);
285 }
286
287 ScopedVector<const HeaderMatchTest> header_tests;
288 for (ListValue::const_iterator it = value_as_list->begin();
289 it != value_as_list->end(); ++it) {
290 const DictionaryValue* tests = NULL;
291 if (!(*it)->GetAsDictionary(&tests)) {
292 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
293 return scoped_ptr<WebRequestConditionAttribute>(NULL);
294 }
295
296 scoped_ptr<const HeaderMatchTest> header_test(
297 CreateHeaderMatchTest(tests, error));
298 if (header_test.get() == NULL)
299 return scoped_ptr<WebRequestConditionAttribute>(NULL);
300 header_tests.push_back(header_test.release());
301 }
302
303 scoped_ptr<WebRequestConditionAttributeResponseHeaders> result;
304 result.reset(new WebRequestConditionAttributeResponseHeaders(
305 name == keys::kResponseHeadersKey, &header_tests));
306
307 return result.PassAs<WebRequestConditionAttribute>();
308 }
309
310 int WebRequestConditionAttributeResponseHeaders::GetStages() const {
311 return ON_HEADERS_RECEIVED;
312 }
313
314 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
315 const WebRequestRule::RequestData& request_data) const {
316 if (!(request_data.stage & GetStages()))
317 return false;
318
319 const net::HttpResponseHeaders* headers =
320 request_data.original_response_headers;
321 if (headers == NULL) {
322 // Each header of an empty set satisfies (the negation of) everything;
323 // OTOH, there is no header to satisfy even the most permissive test.
324 return !positive_test_;
325 }
326
327 // Has some header already passed some header test?
328 bool header_found = false;
329
330 for (size_t i = 0; !header_found && i < tests_.size(); ++i) {
331 std::string name;
332 std::string value;
333
334 void* iter = NULL;
335 while (!header_found &&
336 headers->EnumerateHeaderLines(&iter, &name, &value)) {
337 StringToLowerASCII(&name); // Header names are case-insensitive.
338 header_found |= tests_[i]->Matches(name, value);
339 }
340 }
341
342 return (positive_test_ ? header_found : !header_found);
343 }
344
345 WebRequestConditionAttribute::Type
346 WebRequestConditionAttributeResponseHeaders::GetType() const {
347 return CONDITION_RESPONSE_HEADERS;
348 }
349
350 bool WebRequestConditionAttributeResponseHeaders::StringMatchTest::Matches(
351 const std::string& str) const { 373 const std::string& str) const {
352 switch (type_) { 374 switch (type_) {
353 case kPrefix: 375 case kPrefix:
354 return StartsWithASCII(str, data_, true /*case_sensitive*/); 376 return StartsWithASCII(str, data_, true /*case_sensitive*/);
355 case kSuffix: 377 case kSuffix:
356 return EndsWith(str, data_, true /*case_sensitive*/); 378 return EndsWith(str, data_, true /*case_sensitive*/);
357 case kEquals: 379 case kEquals:
358 return data_ == str; 380 return data_ == str;
359 case kContains: 381 case kContains:
360 return str.find(data_) != std::string::npos; 382 return str.find(data_) != std::string::npos;
383 default:
384 // We never go here, all cases done above. Just to silence the compiler.
385 NOTREACHED();
386 return false;
battre 2012/09/03 08:46:47 I disagree with this change. This makes the compil
vabr (Chromium) 2012/09/03 10:12:36 You're right, reverted. I guess I need to learn to
361 } 387 }
362 // We never get past the "switch", but the compiler worries about no return.
363 NOTREACHED();
364 return false;
365 } 388 }
366 389
367 bool WebRequestConditionAttributeResponseHeaders::HeaderMatchTest::Matches( 390 // HeaderMatcher::HeaderMatchTest implementation.
368 const std::string& name,
369 const std::string& value) const {
370 for (size_t i = 0; i < name_.size(); ++i) {
371 if (!name_[i]->Matches(name))
372 return false;
373 }
374 391
375 for (size_t i = 0; i < value_.size(); ++i) { 392 HeaderMatcher::HeaderMatchTest::HeaderMatchTest(
376 if (!value_[i]->Matches(value)) 393 ScopedVector<const StringMatchTest>* name_match,
377 return false; 394 ScopedVector<const StringMatchTest>* value_match)
378 } 395 : name_match_(name_match->Pass()),
396 value_match_(value_match->Pass()) {}
379 397
380 return true; 398 HeaderMatcher::HeaderMatchTest::~HeaderMatchTest() {}
381 }
382
383 399
384 // static 400 // static
385 scoped_ptr<const WebRequestConditionAttributeResponseHeaders::HeaderMatchTest> 401 scoped_ptr<const HeaderMatcher::HeaderMatchTest>
386 WebRequestConditionAttributeResponseHeaders::CreateHeaderMatchTest( 402 HeaderMatcher::HeaderMatchTest::Create(const base::DictionaryValue* tests) {
387 const DictionaryValue* tests, 403 ScopedVector<const StringMatchTest> name_match;
388 std::string* error) { 404 ScopedVector<const StringMatchTest> value_match;
389 ScopedVector<const StringMatchTest> name;
390 ScopedVector<const StringMatchTest> value;
391 405
392 for (DictionaryValue::key_iterator key = tests->begin_keys(); 406 for (DictionaryValue::key_iterator key = tests->begin_keys();
393 key != tests->end_keys(); 407 key != tests->end_keys();
394 ++key) { 408 ++key) {
395 bool is_name = false; // Is this test for header name? 409 bool is_name = false; // Is this test for header name?
396 MatchType match_type; 410 StringMatchTest::MatchType match_type;
397 if (*key == keys::kNamePrefixKey) { 411 if (*key == keys::kNamePrefixKey) {
398 is_name = true; 412 is_name = true;
399 match_type = kPrefix; 413 match_type = StringMatchTest::kPrefix;
400 } else if (*key == keys::kNameSuffixKey) { 414 } else if (*key == keys::kNameSuffixKey) {
401 is_name = true; 415 is_name = true;
402 match_type = kSuffix; 416 match_type = StringMatchTest::kSuffix;
403 } else if (*key == keys::kNameContainsKey) { 417 } else if (*key == keys::kNameContainsKey) {
404 is_name = true; 418 is_name = true;
405 match_type = kContains; 419 match_type = StringMatchTest::kContains;
406 } else if (*key == keys::kNameEqualsKey) { 420 } else if (*key == keys::kNameEqualsKey) {
407 is_name = true; 421 is_name = true;
408 match_type = kEquals; 422 match_type = StringMatchTest::kEquals;
409 } else if (*key == keys::kValuePrefixKey) { 423 } else if (*key == keys::kValuePrefixKey) {
410 match_type = kPrefix; 424 match_type = StringMatchTest::kPrefix;
411 } else if (*key == keys::kValueSuffixKey) { 425 } else if (*key == keys::kValueSuffixKey) {
412 match_type = kSuffix; 426 match_type = StringMatchTest::kSuffix;
413 } else if (*key == keys::kValueContainsKey) { 427 } else if (*key == keys::kValueContainsKey) {
414 match_type = kContains; 428 match_type = StringMatchTest::kContains;
415 } else if (*key == keys::kValueEqualsKey) { 429 } else if (*key == keys::kValueEqualsKey) {
416 match_type = kEquals; 430 match_type = StringMatchTest::kEquals;
417 } else { 431 } else {
418 NOTREACHED(); // JSON schema type checking should prevent this. 432 NOTREACHED(); // JSON schema type checking should prevent this.
419 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
battre 2012/09/03 08:46:47 why did you remove this?
vabr (Chromium) 2012/09/03 10:12:36 In all situations where creating a HeaderMatchTest
battre 2012/09/03 12:48:08 Thanks. Makes sense.
420 return scoped_ptr<const HeaderMatchTest>(NULL); 433 return scoped_ptr<const HeaderMatchTest>(NULL);
421 } 434 }
422 const Value* content = NULL; 435 const Value* content = NULL;
423 // This should not fire, we already checked that |key| is there. 436 // This should not fire, we already checked that |key| is there.
424 CHECK(tests->Get(*key, &content)); 437 CHECK(tests->Get(*key, &content));
425 438
426 switch (content->GetType()) { 439 switch (content->GetType()) {
427 case Value::TYPE_LIST: { 440 case Value::TYPE_LIST: {
428 const ListValue* list = NULL; 441 const ListValue* list = NULL;
429 CHECK(content->GetAsList(&list)); 442 CHECK(content->GetAsList(&list));
430 for (ListValue::const_iterator it = list->begin(); 443 for (ListValue::const_iterator it = list->begin();
431 it != list->end(); ++it) { 444 it != list->end(); ++it) {
432 ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value; 445 ScopedVector<const StringMatchTest>* tests =
446 is_name ? &name_match : &value_match;
433 tests->push_back( 447 tests->push_back(
434 CreateStringMatchTest(*it, is_name, match_type).release()); 448 StringMatchTest::Create(*it, is_name, match_type).release());
435 } 449 }
436 break; 450 break;
437 } 451 }
438 case Value::TYPE_STRING: { 452 case Value::TYPE_STRING: {
439 ScopedVector<const StringMatchTest>* tests = is_name ? &name : &value; 453 ScopedVector<const StringMatchTest>* tests =
454 is_name ? &name_match : &value_match;
440 tests->push_back( 455 tests->push_back(
441 CreateStringMatchTest(content, is_name, match_type).release()); 456 StringMatchTest::Create(content, is_name, match_type).release());
442 break; 457 break;
443 } 458 }
444 default: { 459 default: {
445 NOTREACHED(); // JSON schema type checking should prevent this. 460 NOTREACHED(); // JSON schema type checking should prevent this.
446 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, *key);
battre 2012/09/03 08:46:47 why did you remove this?
vabr (Chromium) 2012/09/03 10:12:36 Please see above the explanation for HeaderMatchTe
447 return scoped_ptr<const HeaderMatchTest>(NULL); 461 return scoped_ptr<const HeaderMatchTest>(NULL);
448 } 462 }
449 } 463 }
450 } 464 }
451 465
452 return scoped_ptr<const HeaderMatchTest>(new HeaderMatchTest(&name, &value)); 466 return scoped_ptr<const HeaderMatchTest>(
467 new HeaderMatchTest(&name_match, &value_match));
468 }
469
470 bool HeaderMatcher::HeaderMatchTest::Matches(const std::string& name,
471 const std::string& value) const {
472 for (size_t i = 0; i < name_match_.size(); ++i) {
473 if (!name_match_[i]->Matches(name))
474 return false;
475 }
476
477 for (size_t i = 0; i < value_match_.size(); ++i) {
478 if (!value_match_[i]->Matches(value))
479 return false;
480 }
481
482 return true;
483 }
484
485 //
486 // WebRequestConditionAttributeResponseHeaders
487 //
488
489 WebRequestConditionAttributeResponseHeaders::
490 WebRequestConditionAttributeResponseHeaders(
491 scoped_ptr<const HeaderMatcher>* header_matcher, bool positive)
battre 2012/09/03 08:46:47 nit: bool positive goes into next line (either all
vabr (Chromium) 2012/09/03 10:12:36 Done.
492 : header_matcher_(header_matcher->Pass()),
493 positive_(positive) {}
494
495 WebRequestConditionAttributeResponseHeaders::
496 ~WebRequestConditionAttributeResponseHeaders() {}
497
498 // static
499 bool WebRequestConditionAttributeResponseHeaders::IsMatchingType(
500 const std::string& instance_type) {
501 return instance_type == keys::kResponseHeadersKey ||
502 instance_type == keys::kExcludeResponseHeadersKey;
453 } 503 }
454 504
455 // static 505 // static
456 scoped_ptr<const WebRequestConditionAttributeResponseHeaders::StringMatchTest> 506 scoped_ptr<WebRequestConditionAttribute>
457 WebRequestConditionAttributeResponseHeaders::CreateStringMatchTest( 507 WebRequestConditionAttributeResponseHeaders::Create(
458 const Value* content, 508 const std::string& name,
459 bool is_name_test, 509 const base::Value* value,
460 MatchType match_type) { 510 std::string* error) {
461 std::string str; 511 DCHECK(IsMatchingType(name));
462 512
463 CHECK(content->GetAsString(&str)); 513 const ListValue* value_as_list = NULL;
464 if (is_name_test) // Header names are case-insensitive. 514 if (!value->GetAsList(&value_as_list)) {
465 StringToLowerASCII(&str); 515 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
516 return scoped_ptr<WebRequestConditionAttribute>(NULL);
517 }
466 518
467 return scoped_ptr<const StringMatchTest>( 519 scoped_ptr<const HeaderMatcher> header_matcher(
468 new StringMatchTest(str, match_type)); 520 HeaderMatcher::Create(value_as_list));
521 if (header_matcher.get() == NULL) {
522 *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
523 return scoped_ptr<WebRequestConditionAttribute>(NULL);
524 }
525
526 const bool positive = name == keys::kResponseHeadersKey;
battre 2012/09/03 08:46:47 nit: no need for const
vabr (Chromium) 2012/09/03 10:12:36 I disagree. I want to document that |positive| is
battre 2012/09/03 12:48:08 I think the downside is the additional amount of c
527 return scoped_ptr<WebRequestConditionAttribute>(
528 new WebRequestConditionAttributeResponseHeaders(
529 &header_matcher, positive));
530 }
531
532 int WebRequestConditionAttributeResponseHeaders::GetStages() const {
533 return ON_HEADERS_RECEIVED;
534 }
535
536 bool WebRequestConditionAttributeResponseHeaders::IsFulfilled(
537 const WebRequestRule::RequestData& request_data) const {
538 if (!(request_data.stage & GetStages()))
539 return false;
540
541 const net::HttpResponseHeaders* headers =
542 request_data.original_response_headers;
543 if (headers == NULL) {
544 // Each header of an empty set satisfies (the negation of) everything;
545 // OTOH, there is no header to satisfy even the most permissive test.
546 return !positive_;
547 }
548
549 bool passed = false; // Did some header pass TestNameValue?
550 std::string name;
551 std::string value;
552 void* iter = NULL;
553 while (!passed && headers->EnumerateHeaderLines(&iter, &name, &value)) {
554 StringToLowerASCII(&name); // Header names are case-insensitive.
555 passed |= header_matcher_->TestNameValue(name, value);
556 }
557
558 return (positive_ ? passed : !passed);
559 }
560
561 WebRequestConditionAttribute::Type
562 WebRequestConditionAttributeResponseHeaders::GetType() const {
563 return CONDITION_RESPONSE_HEADERS;
469 } 564 }
470 565
471 } // namespace extensions 566 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698