| Index: Source/platform/network/ResourceResponse.cpp
|
| diff --git a/Source/platform/network/ResourceResponse.cpp b/Source/platform/network/ResourceResponse.cpp
|
| index ea22e78ea2851a5411cf9de280c0cf29376ea646..65c53e54cc629678411fd380b1815b1ed4f66e7e 100644
|
| --- a/Source/platform/network/ResourceResponse.cpp
|
| +++ b/Source/platform/network/ResourceResponse.cpp
|
| @@ -27,15 +27,11 @@
|
| #include "config.h"
|
| #include "platform/network/ResourceResponse.h"
|
|
|
| -#include "platform/network/HTTPParsers.h"
|
| #include "wtf/CurrentTime.h"
|
| -#include "wtf/MathExtras.h"
|
| #include "wtf/StdLibExtras.h"
|
|
|
| namespace WebCore {
|
|
|
| -static void parseCacheHeader(const String& header, Vector<pair<String, String> >& result);
|
| -
|
| ResourceResponse::ResourceResponse()
|
| : m_expectedContentLength(0)
|
| , m_httpStatusCode(0)
|
| @@ -44,15 +40,10 @@ ResourceResponse::ResourceResponse()
|
| , m_connectionID(0)
|
| , m_connectionReused(false)
|
| , m_isNull(true)
|
| - , m_haveParsedCacheControlHeader(false)
|
| , m_haveParsedAgeHeader(false)
|
| , m_haveParsedDateHeader(false)
|
| , m_haveParsedExpiresHeader(false)
|
| , m_haveParsedLastModifiedHeader(false)
|
| - , m_cacheControlContainsNoCache(false)
|
| - , m_cacheControlContainsNoStore(false)
|
| - , m_cacheControlContainsMustRevalidate(false)
|
| - , m_cacheControlMaxAge(0.0)
|
| , m_age(0.0)
|
| , m_date(0.0)
|
| , m_expires(0.0)
|
| @@ -81,15 +72,10 @@ ResourceResponse::ResourceResponse(const KURL& url, const AtomicString& mimeType
|
| , m_connectionID(0)
|
| , m_connectionReused(false)
|
| , m_isNull(false)
|
| - , m_haveParsedCacheControlHeader(false)
|
| , m_haveParsedAgeHeader(false)
|
| , m_haveParsedDateHeader(false)
|
| , m_haveParsedExpiresHeader(false)
|
| , m_haveParsedLastModifiedHeader(false)
|
| - , m_cacheControlContainsNoCache(false)
|
| - , m_cacheControlContainsNoStore(false)
|
| - , m_cacheControlContainsMustRevalidate(false)
|
| - , m_cacheControlMaxAge(0.0)
|
| , m_age(0.0)
|
| , m_date(0.0)
|
| , m_expires(0.0)
|
| @@ -277,19 +263,29 @@ const AtomicString& ResourceResponse::httpHeaderField(const char* name) const
|
| return m_httpHeaderFields.get(name);
|
| }
|
|
|
| +static const AtomicString& cacheControlHeaderString()
|
| +{
|
| + DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control", AtomicString::ConstructFromLiteral));
|
| + return cacheControlHeader;
|
| +}
|
| +
|
| +static const AtomicString& pragmaHeaderString()
|
| +{
|
| + DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
|
| + return pragmaHeader;
|
| +}
|
| +
|
| void ResourceResponse::updateHeaderParsedState(const AtomicString& name)
|
| {
|
| DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age", AtomicString::ConstructFromLiteral));
|
| - DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control", AtomicString::ConstructFromLiteral));
|
| DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date", AtomicString::ConstructFromLiteral));
|
| DEFINE_STATIC_LOCAL(const AtomicString, expiresHeader, ("expires", AtomicString::ConstructFromLiteral));
|
| DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified", AtomicString::ConstructFromLiteral));
|
| - DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
|
|
|
| if (equalIgnoringCase(name, ageHeader))
|
| m_haveParsedAgeHeader = false;
|
| - else if (equalIgnoringCase(name, cacheControlHeader) || equalIgnoringCase(name, pragmaHeader))
|
| - m_haveParsedCacheControlHeader = false;
|
| + else if (equalIgnoringCase(name, cacheControlHeaderString()) || equalIgnoringCase(name, pragmaHeaderString()))
|
| + m_cacheControlHeader = CacheControlHeader();
|
| else if (equalIgnoringCase(name, dateHeader))
|
| m_haveParsedDateHeader = false;
|
| else if (equalIgnoringCase(name, expiresHeader))
|
| @@ -324,80 +320,25 @@ const HTTPHeaderMap& ResourceResponse::httpHeaderFields() const
|
| return m_httpHeaderFields;
|
| }
|
|
|
| -void ResourceResponse::parseCacheControlDirectives() const
|
| -{
|
| - ASSERT(!m_haveParsedCacheControlHeader);
|
| -
|
| - m_haveParsedCacheControlHeader = true;
|
| -
|
| - m_cacheControlContainsMustRevalidate = false;
|
| - m_cacheControlContainsNoCache = false;
|
| - m_cacheControlMaxAge = std::numeric_limits<double>::quiet_NaN();
|
| -
|
| - DEFINE_STATIC_LOCAL(const AtomicString, cacheControlString, ("cache-control", AtomicString::ConstructFromLiteral));
|
| - DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache", AtomicString::ConstructFromLiteral));
|
| - DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store", AtomicString::ConstructFromLiteral));
|
| - DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-revalidate", AtomicString::ConstructFromLiteral));
|
| - DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age", AtomicString::ConstructFromLiteral));
|
| -
|
| - const AtomicString& cacheControlValue = m_httpHeaderFields.get(cacheControlString);
|
| - if (!cacheControlValue.isEmpty()) {
|
| - Vector<pair<String, String> > directives;
|
| - parseCacheHeader(cacheControlValue, directives);
|
| -
|
| - size_t directivesSize = directives.size();
|
| - for (size_t i = 0; i < directivesSize; ++i) {
|
| - // RFC2616 14.9.1: A no-cache directive with a value is only meaningful for proxy caches.
|
| - // It should be ignored by a browser level cache.
|
| - if (equalIgnoringCase(directives[i].first, noCacheDirective) && directives[i].second.isEmpty())
|
| - m_cacheControlContainsNoCache = true;
|
| - else if (equalIgnoringCase(directives[i].first, noStoreDirective))
|
| - m_cacheControlContainsNoStore = true;
|
| - else if (equalIgnoringCase(directives[i].first, mustRevalidateDirective))
|
| - m_cacheControlContainsMustRevalidate = true;
|
| - else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) {
|
| - if (!std::isnan(m_cacheControlMaxAge)) {
|
| - // First max-age directive wins if there are multiple ones.
|
| - continue;
|
| - }
|
| - bool ok;
|
| - double maxAge = directives[i].second.toDouble(&ok);
|
| - if (ok)
|
| - m_cacheControlMaxAge = maxAge;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!m_cacheControlContainsNoCache) {
|
| - // Handle Pragma: no-cache
|
| - // This is deprecated and equivalent to Cache-control: no-cache
|
| - // Don't bother tokenizing the value, it is not important
|
| - DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
|
| - const AtomicString& pragmaValue = m_httpHeaderFields.get(pragmaHeader);
|
| -
|
| - m_cacheControlContainsNoCache = pragmaValue.lower().contains(noCacheDirective);
|
| - }
|
| -}
|
| -
|
| -bool ResourceResponse::cacheControlContainsNoCache() const
|
| +bool ResourceResponse::cacheControlContainsNoCache()
|
| {
|
| - if (!m_haveParsedCacheControlHeader)
|
| - parseCacheControlDirectives();
|
| - return m_cacheControlContainsNoCache;
|
| + if (!m_cacheControlHeader.parsed)
|
| + m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
|
| + return m_cacheControlHeader.containsNoCache;
|
| }
|
|
|
| -bool ResourceResponse::cacheControlContainsNoStore() const
|
| +bool ResourceResponse::cacheControlContainsNoStore()
|
| {
|
| - if (!m_haveParsedCacheControlHeader)
|
| - parseCacheControlDirectives();
|
| - return m_cacheControlContainsNoStore;
|
| + if (!m_cacheControlHeader.parsed)
|
| + m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
|
| + return m_cacheControlHeader.containsNoStore;
|
| }
|
|
|
| -bool ResourceResponse::cacheControlContainsMustRevalidate() const
|
| +bool ResourceResponse::cacheControlContainsMustRevalidate()
|
| {
|
| - if (!m_haveParsedCacheControlHeader)
|
| - parseCacheControlDirectives();
|
| - return m_cacheControlContainsMustRevalidate;
|
| + if (!m_cacheControlHeader.parsed)
|
| + m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
|
| + return m_cacheControlHeader.containsMustRevalidate;
|
| }
|
|
|
| bool ResourceResponse::hasCacheValidatorFields() const
|
| @@ -407,11 +348,11 @@ bool ResourceResponse::hasCacheValidatorFields() const
|
| return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeaderFields.get(eTagHeader).isEmpty();
|
| }
|
|
|
| -double ResourceResponse::cacheControlMaxAge() const
|
| +double ResourceResponse::cacheControlMaxAge()
|
| {
|
| - if (!m_haveParsedCacheControlHeader)
|
| - parseCacheControlDirectives();
|
| - return m_cacheControlMaxAge;
|
| + if (!m_cacheControlHeader.parsed)
|
| + m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
|
| + return m_cacheControlHeader.maxAge;
|
| }
|
|
|
| static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicString& headerName)
|
| @@ -585,99 +526,4 @@ bool ResourceResponse::compare(const ResourceResponse& a, const ResourceResponse
|
| return true;
|
| }
|
|
|
| -static bool isCacheHeaderSeparator(UChar c)
|
| -{
|
| - // See RFC 2616, Section 2.2
|
| - switch (c) {
|
| - case '(':
|
| - case ')':
|
| - case '<':
|
| - case '>':
|
| - case '@':
|
| - case ',':
|
| - case ';':
|
| - case ':':
|
| - case '\\':
|
| - case '"':
|
| - case '/':
|
| - case '[':
|
| - case ']':
|
| - case '?':
|
| - case '=':
|
| - case '{':
|
| - case '}':
|
| - case ' ':
|
| - case '\t':
|
| - return true;
|
| - default:
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -static bool isControlCharacter(UChar c)
|
| -{
|
| - return c < ' ' || c == 127;
|
| -}
|
| -
|
| -static inline String trimToNextSeparator(const String& str)
|
| -{
|
| - return str.substring(0, str.find(isCacheHeaderSeparator));
|
| -}
|
| -
|
| -static void parseCacheHeader(const String& header, Vector<pair<String, String> >& result)
|
| -{
|
| - const String safeHeader = header.removeCharacters(isControlCharacter);
|
| - unsigned max = safeHeader.length();
|
| - for (unsigned pos = 0; pos < max; /* pos incremented in loop */) {
|
| - size_t nextCommaPosition = safeHeader.find(',', pos);
|
| - size_t nextEqualSignPosition = safeHeader.find('=', pos);
|
| - if (nextEqualSignPosition != kNotFound && (nextEqualSignPosition < nextCommaPosition || nextCommaPosition == kNotFound)) {
|
| - // Get directive name, parse right hand side of equal sign, then add to map
|
| - String directive = trimToNextSeparator(safeHeader.substring(pos, nextEqualSignPosition - pos).stripWhiteSpace());
|
| - pos += nextEqualSignPosition - pos + 1;
|
| -
|
| - String value = safeHeader.substring(pos, max - pos).stripWhiteSpace();
|
| - if (value[0] == '"') {
|
| - // The value is a quoted string
|
| - size_t nextDoubleQuotePosition = value.find('"', 1);
|
| - if (nextDoubleQuotePosition != kNotFound) {
|
| - // Store the value as a quoted string without quotes
|
| - result.append(pair<String, String>(directive, value.substring(1, nextDoubleQuotePosition - 1).stripWhiteSpace()));
|
| - pos += (safeHeader.find('"', pos) - pos) + nextDoubleQuotePosition + 1;
|
| - // Move past next comma, if there is one
|
| - size_t nextCommaPosition2 = safeHeader.find(',', pos);
|
| - if (nextCommaPosition2 != kNotFound)
|
| - pos += nextCommaPosition2 - pos + 1;
|
| - else
|
| - return; // Parse error if there is anything left with no comma
|
| - } else {
|
| - // Parse error; just use the rest as the value
|
| - result.append(pair<String, String>(directive, trimToNextSeparator(value.substring(1, value.length() - 1).stripWhiteSpace())));
|
| - return;
|
| - }
|
| - } else {
|
| - // The value is a token until the next comma
|
| - size_t nextCommaPosition2 = value.find(',');
|
| - if (nextCommaPosition2 != kNotFound) {
|
| - // The value is delimited by the next comma
|
| - result.append(pair<String, String>(directive, trimToNextSeparator(value.substring(0, nextCommaPosition2).stripWhiteSpace())));
|
| - pos += (safeHeader.find(',', pos) - pos) + 1;
|
| - } else {
|
| - // The rest is the value; no change to value needed
|
| - result.append(pair<String, String>(directive, trimToNextSeparator(value)));
|
| - return;
|
| - }
|
| - }
|
| - } else if (nextCommaPosition != kNotFound && (nextCommaPosition < nextEqualSignPosition || nextEqualSignPosition == kNotFound)) {
|
| - // Add directive to map with empty string as value
|
| - result.append(pair<String, String>(trimToNextSeparator(safeHeader.substring(pos, nextCommaPosition - pos).stripWhiteSpace()), ""));
|
| - pos += nextCommaPosition - pos + 1;
|
| - } else {
|
| - // Add last directive to map with empty string as value
|
| - result.append(pair<String, String>(trimToNextSeparator(safeHeader.substring(pos, max - pos).stripWhiteSpace()), ""));
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| }
|
|
|