static double freshnessLifetime(ResourceResponse& response, double responseTimestamp) { #if !OS(ANDROID) // On desktop, local files should be reloaded in case they change. if (response.url().isLocalFile()) return 0; #endif // Cache other non-http / non-filesystem resources liberally. if (!response.url().protocolIsInHTTPFamily() && !response.url().protocolIs("filesystem")) return std::numeric_limits<double>::max(); // RFC2616 13.2.4 double maxAgeValue = response.cacheControlMaxAge(); if (std::isfinite(maxAgeValue)) return maxAgeValue; double expiresValue = response.expires(); double dateValue = response.date(); double creationTime = std::isfinite(dateValue) ? dateValue : responseTimestamp; if (std::isfinite(expiresValue)) return expiresValue - creationTime; double lastModifiedValue = response.lastModified(); if (std::isfinite(lastModifiedValue)) return (creationTime - lastModifiedValue) * 0.1; // If no cache headers are present, the specification leaves the decision to the UA. Other browsers seem to opt for 0. return 0; }
static bool canUseResponse(ResourceResponse& response, double responseTimestamp) { if (response.isNull()) return false; // FIXME: Why isn't must-revalidate considered a reason we can't use the response? if (response.cacheControlContainsNoCache() || response.cacheControlContainsNoStore()) return false; if (response.httpStatusCode() == 303) { // Must not be cached. return false; } if (response.httpStatusCode() == 302 || response.httpStatusCode() == 307) { // Default to not cacheable unless explicitly allowed. bool hasMaxAge = std::isfinite(response.cacheControlMaxAge()); bool hasExpires = std::isfinite(response.expires()); // TODO: consider catching Cache-Control "private" and "public" here. if (!hasMaxAge && !hasExpires) return false; } return currentAge(response, responseTimestamp) <= freshnessLifetime(response, responseTimestamp); }
bool CurlCacheEntry::parseResponseHeaders(ResourceResponse& response) { double fileTime; time_t fileModificationDate; if (getFileModificationTime(m_headerFilename, fileModificationDate)) { fileTime = difftime(fileModificationDate, 0); fileTime *= 1000.0; } else fileTime = currentTimeMS(); // GMT if (response.cacheControlContainsNoCache() || response.cacheControlContainsNoStore()) return false; double maxAge = 0; bool maxAgeIsValid = false; if (response.cacheControlContainsMustRevalidate()) maxAge = 0; else { maxAge = response.cacheControlMaxAge(); if (std::isnan(maxAge)) maxAge = 0; else maxAgeIsValid = true; } if (!response.hasCacheValidatorFields()) return false; double lastModificationDate = 0; double responseDate = 0; double expirationDate = 0; lastModificationDate = response.lastModified(); if (std::isnan(lastModificationDate)) lastModificationDate = 0; responseDate = response.date(); if (std::isnan(responseDate)) responseDate = 0; expirationDate = response.expires(); if (std::isnan(expirationDate)) expirationDate = 0; if (maxAgeIsValid) { // when both the cache entry and the response contain max-age, the lesser one takes priority double expires = fileTime + maxAge * 1000; if (m_expireDate == -1 || m_expireDate > expires) m_expireDate = expires; } else if (responseDate > 0 && expirationDate >= responseDate) m_expireDate = fileTime + (expirationDate - responseDate); // if there were no lifetime information if (m_expireDate == -1) { if (lastModificationDate > 0) m_expireDate = fileTime + (fileTime - lastModificationDate) * 0.1; else m_expireDate = 0; } String etag = response.httpHeaderField("ETag"); if (!etag.isNull()) m_requestHeaders.set("If-None-Match", etag); String lastModified = response.httpHeaderField("Last-Modified"); if (!lastModified.isNull()) m_requestHeaders.set("If-Modified-Since", lastModified); if (etag.isNull() && lastModified.isNull()) return false; m_headerInMemory = true; return true; }