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; |
- } |
- } |
-} |
- |
} |