| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | 2 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
| 3 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. | 3 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. |
| 4 * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ | 4 * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ |
| 5 * Copyright (C) 2009 Google Inc. All rights reserved. | 5 * Copyright (C) 2009 Google Inc. All rights reserved. |
| 6 * Copyright (C) 2011 Apple Inc. All Rights Reserved. | 6 * Copyright (C) 2011 Apple Inc. All Rights Reserved. |
| 7 * | 7 * |
| 8 * Redistribution and use in source and binary forms, with or without | 8 * Redistribution and use in source and binary forms, with or without |
| 9 * modification, are permitted provided that the following conditions | 9 * modification, are permitted provided that the following conditions |
| 10 * are met: | 10 * are met: |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 UChar firstCharacter = value[0]; | 206 UChar firstCharacter = value[0]; |
| 207 if (firstCharacter == ' ' || firstCharacter == '\t') | 207 if (firstCharacter == ' ' || firstCharacter == '\t') |
| 208 return false; | 208 return false; |
| 209 | 209 |
| 210 UChar lastCharacter = value[value.length() - 1]; | 210 UChar lastCharacter = value[value.length() - 1]; |
| 211 if (lastCharacter == ' ' || lastCharacter == '\t') | 211 if (lastCharacter == ' ' || lastCharacter == '\t') |
| 212 return false; | 212 return false; |
| 213 | 213 |
| 214 for (unsigned i = 0; i < value.length(); ++i) { | 214 for (unsigned i = 0; i < value.length(); ++i) { |
| 215 UChar c = value[i]; | 215 UChar c = value[i]; |
| 216 // TODO(mkwst): Extract this character class to a central location, https://
crbug.com/527324. | 216 // TODO(mkwst): Extract this character class to a central location, |
| 217 // https://crbug.com/527324. |
| 217 if (c == 0x7F || c > 0xFF || (c < 0x20 && c != '\t')) | 218 if (c == 0x7F || c > 0xFF || (c < 0x20 && c != '\t')) |
| 218 return false; | 219 return false; |
| 219 } | 220 } |
| 220 | 221 |
| 221 return true; | 222 return true; |
| 222 } | 223 } |
| 223 | 224 |
| 224 // See RFC 7230, Section 3.2.6. | 225 // See RFC 7230, Section 3.2.6. |
| 225 bool isValidHTTPToken(const String& characters) { | 226 bool isValidHTTPToken(const String& characters) { |
| 226 if (characters.isEmpty()) | 227 if (characters.isEmpty()) |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 if (refresh[urlStartPos] == '"' || refresh[urlStartPos] == '\'') { | 314 if (refresh[urlStartPos] == '"' || refresh[urlStartPos] == '\'') { |
| 314 UChar quotationMark = refresh[urlStartPos]; | 315 UChar quotationMark = refresh[urlStartPos]; |
| 315 urlStartPos++; | 316 urlStartPos++; |
| 316 while (urlEndPos > urlStartPos) { | 317 while (urlEndPos > urlStartPos) { |
| 317 urlEndPos--; | 318 urlEndPos--; |
| 318 if (refresh[urlEndPos] == quotationMark) | 319 if (refresh[urlEndPos] == quotationMark) |
| 319 break; | 320 break; |
| 320 } | 321 } |
| 321 | 322 |
| 322 // https://bugs.webkit.org/show_bug.cgi?id=27868 | 323 // https://bugs.webkit.org/show_bug.cgi?id=27868 |
| 323 // Sometimes there is no closing quote for the end of the URL even though
there was an opening quote. | 324 // Sometimes there is no closing quote for the end of the URL even though |
| 324 // If we looped over the entire alleged URL string back to the opening quo
te, just go ahead and use everything | 325 // there was an opening quote. If we looped over the entire alleged URL |
| 326 // string back to the opening quote, just go ahead and use everything |
| 325 // after the opening quote instead. | 327 // after the opening quote instead. |
| 326 if (urlEndPos == urlStartPos) | 328 if (urlEndPos == urlStartPos) |
| 327 urlEndPos = len; | 329 urlEndPos = len; |
| 328 } | 330 } |
| 329 | 331 |
| 330 url = refresh.substring(urlStartPos, urlEndPos - urlStartPos) | 332 url = refresh.substring(urlStartPos, urlEndPos - urlStartPos) |
| 331 .stripWhiteSpace(); | 333 .stripWhiteSpace(); |
| 332 return true; | 334 return true; |
| 333 } | 335 } |
| 334 } | 336 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 351 | 353 |
| 352 if (pos == length) | 354 if (pos == length) |
| 353 return mediaType; | 355 return mediaType; |
| 354 | 356 |
| 355 unsigned typeStart = pos; | 357 unsigned typeStart = pos; |
| 356 | 358 |
| 357 unsigned typeEnd = pos; | 359 unsigned typeEnd = pos; |
| 358 while (pos < length) { | 360 while (pos < length) { |
| 359 UChar c = mediaType[pos]; | 361 UChar c = mediaType[pos]; |
| 360 | 362 |
| 361 // While RFC 2616 does not allow it, other browsers allow multiple values in
the HTTP media | 363 // While RFC 2616 does not allow it, other browsers allow multiple values in |
| 362 // type header field, Content-Type. In such cases, the media type string pas
sed here may contain | 364 // the HTTP media type header field, Content-Type. In such cases, the media |
| 363 // the multiple values separated by commas. For now, this code ignores text
after the first comma, | 365 // type string passed here may contain the multiple values separated by |
| 364 // which prevents it from simply failing to parse such types altogether. Lat
er for better | 366 // commas. For now, this code ignores text after the first comma, which |
| 365 // compatibility we could consider using the first or last valid MIME type i
nstead. | 367 // prevents it from simply failing to parse such types altogether. Later |
| 368 // for better compatibility we could consider using the first or last valid |
| 369 // MIME type instead. |
| 366 // See https://bugs.webkit.org/show_bug.cgi?id=25352 for more discussion. | 370 // See https://bugs.webkit.org/show_bug.cgi?id=25352 for more discussion. |
| 367 if (c == ',' || c == ';') | 371 if (c == ',' || c == ';') |
| 368 break; | 372 break; |
| 369 | 373 |
| 370 if (c != '\t' && c != ' ') | 374 if (c != '\t' && c != ' ') |
| 371 typeEnd = pos + 1; | 375 typeEnd = pos + 1; |
| 372 | 376 |
| 373 ++pos; | 377 ++pos; |
| 374 } | 378 } |
| 375 | 379 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 405 pos += 7; | 409 pos += 7; |
| 406 continue; | 410 continue; |
| 407 } | 411 } |
| 408 | 412 |
| 409 pos += 7; | 413 pos += 7; |
| 410 | 414 |
| 411 // skip whitespace | 415 // skip whitespace |
| 412 while (pos != length && mediaType[pos] <= ' ') | 416 while (pos != length && mediaType[pos] <= ' ') |
| 413 ++pos; | 417 ++pos; |
| 414 | 418 |
| 415 if (mediaType[pos++] != | 419 if (mediaType[pos++] != '=') // this "charset" substring wasn't a parameter |
| 416 '=') // this "charset" substring wasn't a parameter name, but there may
be others | 420 // name, but there may be others |
| 417 continue; | 421 continue; |
| 418 | 422 |
| 419 while (pos != length && (mediaType[pos] <= ' ' || mediaType[pos] == '"' || | 423 while (pos != length && (mediaType[pos] <= ' ' || mediaType[pos] == '"' || |
| 420 mediaType[pos] == '\'')) | 424 mediaType[pos] == '\'')) |
| 421 ++pos; | 425 ++pos; |
| 422 | 426 |
| 423 // we don't handle spaces within quoted parameter values, because charset na
mes cannot have any | 427 // we don't handle spaces within quoted parameter values, because charset |
| 428 // names cannot have any |
| 424 unsigned endpos = pos; | 429 unsigned endpos = pos; |
| 425 while (pos != length && mediaType[endpos] > ' ' && | 430 while (pos != length && mediaType[endpos] > ' ' && |
| 426 mediaType[endpos] != '"' && mediaType[endpos] != '\'' && | 431 mediaType[endpos] != '"' && mediaType[endpos] != '\'' && |
| 427 mediaType[endpos] != ';') | 432 mediaType[endpos] != ';') |
| 428 ++endpos; | 433 ++endpos; |
| 429 | 434 |
| 430 charsetPos = pos; | 435 charsetPos = pos; |
| 431 charsetLen = endpos - pos; | 436 charsetLen = endpos - pos; |
| 432 return; | 437 return; |
| 433 } | 438 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 464 if (header[pos++] != '1') { | 469 if (header[pos++] != '1') { |
| 465 failureReason = failureReasonInvalidToggle; | 470 failureReason = failureReasonInvalidToggle; |
| 466 return ReflectedXSSInvalid; | 471 return ReflectedXSSInvalid; |
| 467 } | 472 } |
| 468 | 473 |
| 469 ReflectedXSSDisposition result = FilterReflectedXSS; | 474 ReflectedXSSDisposition result = FilterReflectedXSS; |
| 470 bool modeDirectiveSeen = false; | 475 bool modeDirectiveSeen = false; |
| 471 bool reportDirectiveSeen = false; | 476 bool reportDirectiveSeen = false; |
| 472 | 477 |
| 473 while (1) { | 478 while (1) { |
| 474 // At end of previous directive: consume whitespace, semicolon, and whitespa
ce. | 479 // At end of previous directive: consume whitespace, semicolon, and |
| 480 // whitespace. |
| 475 if (!skipWhiteSpace(header, pos)) | 481 if (!skipWhiteSpace(header, pos)) |
| 476 return result; | 482 return result; |
| 477 | 483 |
| 478 if (header[pos++] != ';') { | 484 if (header[pos++] != ';') { |
| 479 failureReason = failureReasonInvalidSeparator; | 485 failureReason = failureReasonInvalidSeparator; |
| 480 failurePosition = pos; | 486 failurePosition = pos; |
| 481 return ReflectedXSSInvalid; | 487 return ReflectedXSSInvalid; |
| 482 } | 488 } |
| 483 | 489 |
| 484 if (!skipWhiteSpace(header, pos)) | 490 if (!skipWhiteSpace(header, pos)) |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 static void parseCacheHeader(const String& header, | 613 static void parseCacheHeader(const String& header, |
| 608 Vector<std::pair<String, String>>& result) { | 614 Vector<std::pair<String, String>>& result) { |
| 609 const String safeHeader = header.removeCharacters(isControlCharacter); | 615 const String safeHeader = header.removeCharacters(isControlCharacter); |
| 610 unsigned max = safeHeader.length(); | 616 unsigned max = safeHeader.length(); |
| 611 for (unsigned pos = 0; pos < max; /* pos incremented in loop */) { | 617 for (unsigned pos = 0; pos < max; /* pos incremented in loop */) { |
| 612 size_t nextCommaPosition = safeHeader.find(',', pos); | 618 size_t nextCommaPosition = safeHeader.find(',', pos); |
| 613 size_t nextEqualSignPosition = safeHeader.find('=', pos); | 619 size_t nextEqualSignPosition = safeHeader.find('=', pos); |
| 614 if (nextEqualSignPosition != kNotFound && | 620 if (nextEqualSignPosition != kNotFound && |
| 615 (nextEqualSignPosition < nextCommaPosition || | 621 (nextEqualSignPosition < nextCommaPosition || |
| 616 nextCommaPosition == kNotFound)) { | 622 nextCommaPosition == kNotFound)) { |
| 617 // Get directive name, parse right hand side of equal sign, then add to ma
p | 623 // Get directive name, parse right hand side of equal sign, then add to |
| 624 // map |
| 618 String directive = trimToNextSeparator( | 625 String directive = trimToNextSeparator( |
| 619 safeHeader.substring(pos, nextEqualSignPosition - pos) | 626 safeHeader.substring(pos, nextEqualSignPosition - pos) |
| 620 .stripWhiteSpace()); | 627 .stripWhiteSpace()); |
| 621 pos += nextEqualSignPosition - pos + 1; | 628 pos += nextEqualSignPosition - pos + 1; |
| 622 | 629 |
| 623 String value = safeHeader.substring(pos, max - pos).stripWhiteSpace(); | 630 String value = safeHeader.substring(pos, max - pos).stripWhiteSpace(); |
| 624 if (value[0] == '"') { | 631 if (value[0] == '"') { |
| 625 // The value is a quoted string | 632 // The value is a quoted string |
| 626 size_t nextDoubleQuotePosition = value.find('"', 1); | 633 size_t nextDoubleQuotePosition = value.find('"', 1); |
| 627 if (nextDoubleQuotePosition != kNotFound) { | 634 if (nextDoubleQuotePosition != kNotFound) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age")); | 705 DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age")); |
| 699 DEFINE_STATIC_LOCAL(const AtomicString, staleWhileRevalidateDirective, | 706 DEFINE_STATIC_LOCAL(const AtomicString, staleWhileRevalidateDirective, |
| 700 ("stale-while-revalidate")); | 707 ("stale-while-revalidate")); |
| 701 | 708 |
| 702 if (!cacheControlValue.isEmpty()) { | 709 if (!cacheControlValue.isEmpty()) { |
| 703 Vector<std::pair<String, String>> directives; | 710 Vector<std::pair<String, String>> directives; |
| 704 parseCacheHeader(cacheControlValue, directives); | 711 parseCacheHeader(cacheControlValue, directives); |
| 705 | 712 |
| 706 size_t directivesSize = directives.size(); | 713 size_t directivesSize = directives.size(); |
| 707 for (size_t i = 0; i < directivesSize; ++i) { | 714 for (size_t i = 0; i < directivesSize; ++i) { |
| 708 // RFC2616 14.9.1: A no-cache directive with a value is only meaningful fo
r proxy caches. | 715 // RFC2616 14.9.1: A no-cache directive with a value is only meaningful |
| 709 // It should be ignored by a browser level cache. | 716 // for proxy caches. It should be ignored by a browser level cache. |
| 710 if (equalIgnoringCase(directives[i].first, noCacheDirective) && | 717 if (equalIgnoringCase(directives[i].first, noCacheDirective) && |
| 711 directives[i].second.isEmpty()) { | 718 directives[i].second.isEmpty()) { |
| 712 cacheControlHeader.containsNoCache = true; | 719 cacheControlHeader.containsNoCache = true; |
| 713 } else if (equalIgnoringCase(directives[i].first, noStoreDirective)) { | 720 } else if (equalIgnoringCase(directives[i].first, noStoreDirective)) { |
| 714 cacheControlHeader.containsNoStore = true; | 721 cacheControlHeader.containsNoStore = true; |
| 715 } else if (equalIgnoringCase(directives[i].first, | 722 } else if (equalIgnoringCase(directives[i].first, |
| 716 mustRevalidateDirective)) { | 723 mustRevalidateDirective)) { |
| 717 cacheControlHeader.containsMustRevalidate = true; | 724 cacheControlHeader.containsMustRevalidate = true; |
| 718 } else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) { | 725 } else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) { |
| 719 if (!std::isnan(cacheControlHeader.maxAge)) { | 726 if (!std::isnan(cacheControlHeader.maxAge)) { |
| 720 // First max-age directive wins if there are multiple ones. | 727 // First max-age directive wins if there are multiple ones. |
| 721 continue; | 728 continue; |
| 722 } | 729 } |
| 723 bool ok; | 730 bool ok; |
| 724 double maxAge = directives[i].second.toDouble(&ok); | 731 double maxAge = directives[i].second.toDouble(&ok); |
| 725 if (ok) | 732 if (ok) |
| 726 cacheControlHeader.maxAge = maxAge; | 733 cacheControlHeader.maxAge = maxAge; |
| 727 } else if (equalIgnoringCase(directives[i].first, | 734 } else if (equalIgnoringCase(directives[i].first, |
| 728 staleWhileRevalidateDirective)) { | 735 staleWhileRevalidateDirective)) { |
| 729 if (!std::isnan(cacheControlHeader.staleWhileRevalidate)) { | 736 if (!std::isnan(cacheControlHeader.staleWhileRevalidate)) { |
| 730 // First stale-while-revalidate directive wins if there are multiple o
nes. | 737 // First stale-while-revalidate directive wins if there are multiple |
| 738 // ones. |
| 731 continue; | 739 continue; |
| 732 } | 740 } |
| 733 bool ok; | 741 bool ok; |
| 734 double staleWhileRevalidate = directives[i].second.toDouble(&ok); | 742 double staleWhileRevalidate = directives[i].second.toDouble(&ok); |
| 735 if (ok) | 743 if (ok) |
| 736 cacheControlHeader.staleWhileRevalidate = staleWhileRevalidate; | 744 cacheControlHeader.staleWhileRevalidate = staleWhileRevalidate; |
| 737 } | 745 } |
| 738 } | 746 } |
| 739 } | 747 } |
| 740 | 748 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 messages.append("Ignoring unknown suborigin policy option " + optionName + | 808 messages.append("Ignoring unknown suborigin policy option " + optionName + |
| 801 "."); | 809 "."); |
| 802 else | 810 else |
| 803 suborigin->addPolicyOption(option); | 811 suborigin->addPolicyOption(option); |
| 804 } | 812 } |
| 805 | 813 |
| 806 return true; | 814 return true; |
| 807 } | 815 } |
| 808 | 816 |
| 809 } // namespace blink | 817 } // namespace blink |
| OLD | NEW |