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 |