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 16 matching lines...) Expand all Loading... |
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 */ | 31 */ |
32 | 32 |
33 #include "config.h" | 33 #include "config.h" |
34 #include "platform/network/HTTPParsers.h" | 34 #include "platform/network/HTTPParsers.h" |
35 | 35 |
36 #include "wtf/DateMath.h" | 36 #include "wtf/DateMath.h" |
| 37 #include "wtf/MathExtras.h" |
37 #include "wtf/text/CString.h" | 38 #include "wtf/text/CString.h" |
38 #include "wtf/text/StringBuilder.h" | 39 #include "wtf/text/StringBuilder.h" |
39 #include "wtf/text/WTFString.h" | 40 #include "wtf/text/WTFString.h" |
40 #include "wtf/unicode/CharacterNames.h" | 41 #include "wtf/unicode/CharacterNames.h" |
41 | 42 |
42 using namespace WTF; | 43 using namespace WTF; |
43 | 44 |
44 namespace WebCore { | 45 namespace WebCore { |
45 | 46 |
46 // true if there is more to parse, after incrementing pos past whitespace. | 47 // true if there is more to parse, after incrementing pos past whitespace. |
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 } | 678 } |
678 | 679 |
679 size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned cha
r>& body) | 680 size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned cha
r>& body) |
680 { | 681 { |
681 body.clear(); | 682 body.clear(); |
682 body.append(data, length); | 683 body.append(data, length); |
683 | 684 |
684 return length; | 685 return length; |
685 } | 686 } |
686 | 687 |
| 688 static bool isCacheHeaderSeparator(UChar c) |
| 689 { |
| 690 // See RFC 2616, Section 2.2 |
| 691 switch (c) { |
| 692 case '(': |
| 693 case ')': |
| 694 case '<': |
| 695 case '>': |
| 696 case '@': |
| 697 case ',': |
| 698 case ';': |
| 699 case ':': |
| 700 case '\\': |
| 701 case '"': |
| 702 case '/': |
| 703 case '[': |
| 704 case ']': |
| 705 case '?': |
| 706 case '=': |
| 707 case '{': |
| 708 case '}': |
| 709 case ' ': |
| 710 case '\t': |
| 711 return true; |
| 712 default: |
| 713 return false; |
| 714 } |
687 } | 715 } |
| 716 |
| 717 static bool isControlCharacter(UChar c) |
| 718 { |
| 719 return c < ' ' || c == 127; |
| 720 } |
| 721 |
| 722 static inline String trimToNextSeparator(const String& str) |
| 723 { |
| 724 return str.substring(0, str.find(isCacheHeaderSeparator)); |
| 725 } |
| 726 |
| 727 static void parseCacheHeader(const String& header, Vector<pair<String, String> >
& result) |
| 728 { |
| 729 const String safeHeader = header.removeCharacters(isControlCharacter); |
| 730 unsigned max = safeHeader.length(); |
| 731 for (unsigned pos = 0; pos < max; /* pos incremented in loop */) { |
| 732 size_t nextCommaPosition = safeHeader.find(',', pos); |
| 733 size_t nextEqualSignPosition = safeHeader.find('=', pos); |
| 734 if (nextEqualSignPosition != kNotFound && (nextEqualSignPosition < nextC
ommaPosition || nextCommaPosition == kNotFound)) { |
| 735 // Get directive name, parse right hand side of equal sign, then add
to map |
| 736 String directive = trimToNextSeparator(safeHeader.substring(pos, nex
tEqualSignPosition - pos).stripWhiteSpace()); |
| 737 pos += nextEqualSignPosition - pos + 1; |
| 738 |
| 739 String value = safeHeader.substring(pos, max - pos).stripWhiteSpace(
); |
| 740 if (value[0] == '"') { |
| 741 // The value is a quoted string |
| 742 size_t nextDoubleQuotePosition = value.find('"', 1); |
| 743 if (nextDoubleQuotePosition != kNotFound) { |
| 744 // Store the value as a quoted string without quotes |
| 745 result.append(pair<String, String>(directive, value.substrin
g(1, nextDoubleQuotePosition - 1).stripWhiteSpace())); |
| 746 pos += (safeHeader.find('"', pos) - pos) + nextDoubleQuotePo
sition + 1; |
| 747 // Move past next comma, if there is one |
| 748 size_t nextCommaPosition2 = safeHeader.find(',', pos); |
| 749 if (nextCommaPosition2 != kNotFound) |
| 750 pos += nextCommaPosition2 - pos + 1; |
| 751 else |
| 752 return; // Parse error if there is anything left with no
comma |
| 753 } else { |
| 754 // Parse error; just use the rest as the value |
| 755 result.append(pair<String, String>(directive, trimToNextSepa
rator(value.substring(1, value.length() - 1).stripWhiteSpace()))); |
| 756 return; |
| 757 } |
| 758 } else { |
| 759 // The value is a token until the next comma |
| 760 size_t nextCommaPosition2 = value.find(','); |
| 761 if (nextCommaPosition2 != kNotFound) { |
| 762 // The value is delimited by the next comma |
| 763 result.append(pair<String, String>(directive, trimToNextSepa
rator(value.substring(0, nextCommaPosition2).stripWhiteSpace()))); |
| 764 pos += (safeHeader.find(',', pos) - pos) + 1; |
| 765 } else { |
| 766 // The rest is the value; no change to value needed |
| 767 result.append(pair<String, String>(directive, trimToNextSepa
rator(value))); |
| 768 return; |
| 769 } |
| 770 } |
| 771 } else if (nextCommaPosition != kNotFound && (nextCommaPosition < nextEq
ualSignPosition || nextEqualSignPosition == kNotFound)) { |
| 772 // Add directive to map with empty string as value |
| 773 result.append(pair<String, String>(trimToNextSeparator(safeHeader.su
bstring(pos, nextCommaPosition - pos).stripWhiteSpace()), "")); |
| 774 pos += nextCommaPosition - pos + 1; |
| 775 } else { |
| 776 // Add last directive to map with empty string as value |
| 777 result.append(pair<String, String>(trimToNextSeparator(safeHeader.su
bstring(pos, max - pos).stripWhiteSpace()), "")); |
| 778 return; |
| 779 } |
| 780 } |
| 781 } |
| 782 |
| 783 CacheControlHeader parseCacheControlDirectives(const AtomicString& cacheControlV
alue, const AtomicString& pragmaValue) |
| 784 { |
| 785 CacheControlHeader cacheControlHeader; |
| 786 cacheControlHeader.parsed = true; |
| 787 cacheControlHeader.maxAge = std::numeric_limits<double>::quiet_NaN(); |
| 788 |
| 789 DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache", Atomi
cString::ConstructFromLiteral)); |
| 790 DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store", Atomi
cString::ConstructFromLiteral)); |
| 791 DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-reva
lidate", AtomicString::ConstructFromLiteral)); |
| 792 DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age", AtomicS
tring::ConstructFromLiteral)); |
| 793 |
| 794 if (!cacheControlValue.isEmpty()) { |
| 795 Vector<pair<String, String> > directives; |
| 796 parseCacheHeader(cacheControlValue, directives); |
| 797 |
| 798 size_t directivesSize = directives.size(); |
| 799 for (size_t i = 0; i < directivesSize; ++i) { |
| 800 // RFC2616 14.9.1: A no-cache directive with a value is only meaning
ful for proxy caches. |
| 801 // It should be ignored by a browser level cache. |
| 802 if (equalIgnoringCase(directives[i].first, noCacheDirective) && dire
ctives[i].second.isEmpty()) { |
| 803 cacheControlHeader.containsNoCache = true; |
| 804 } else if (equalIgnoringCase(directives[i].first, noStoreDirective))
{ |
| 805 cacheControlHeader.containsNoStore = true; |
| 806 } else if (equalIgnoringCase(directives[i].first, mustRevalidateDire
ctive)) { |
| 807 cacheControlHeader.containsMustRevalidate = true; |
| 808 } else if (equalIgnoringCase(directives[i].first, maxAgeDirective))
{ |
| 809 if (!std::isnan(cacheControlHeader.maxAge)) { |
| 810 // First max-age directive wins if there are multiple ones. |
| 811 continue; |
| 812 } |
| 813 bool ok; |
| 814 double maxAge = directives[i].second.toDouble(&ok); |
| 815 if (ok) |
| 816 cacheControlHeader.maxAge = maxAge; |
| 817 } |
| 818 } |
| 819 } |
| 820 |
| 821 if (!cacheControlHeader.containsNoCache) { |
| 822 // Handle Pragma: no-cache |
| 823 // This is deprecated and equivalent to Cache-control: no-cache |
| 824 // Don't bother tokenizing the value, it is not important |
| 825 cacheControlHeader.containsNoCache = pragmaValue.lower().contains(noCach
eDirective); |
| 826 } |
| 827 return cacheControlHeader; |
| 828 } |
| 829 |
| 830 } |
OLD | NEW |