Changeset 201800 in webkit


Ignore:
Timestamp:
Jun 8, 2016 2:01:07 AM (8 years ago)
Author:
Antti Koivisto
Message:

WebKit memory cache doesn't respect Vary header
https://bugs.webkit.org/show_bug.cgi?id=71509
<rdar://problem/26651033>

Reviewed by Sam Weinig.

Implement Vary header support in WebCore memory cache.

The patch moves Vary header code from WebKit2 Network Cache to WebCore and uses it to
verify the headers for CachedResources.

  • loader/cache/CachedResource.cpp:

(WebCore::CachedResource::failBeforeStarting):
(WebCore::addAdditionalRequestHeadersToRequest):

Factor into standalone function so we can use it from varyHeaderValuesMatch.

(WebCore::CachedResource::addAdditionalRequestHeaders):
(WebCore::CachedResource::load):
(WebCore::CachedResource::setResponse):

Collect the Vary header values when we receive a response.

(WebCore::CachedResource::responseReceived):
(WebCore::CachedResource::redirectChainAllowsReuse):
(WebCore::CachedResource::varyHeaderValuesMatch):

Test for Vary match.

(WebCore::CachedResource::overheadSize):

  • loader/cache/CachedResource.h:

(WebCore::CachedResource::isCacheValidator):
(WebCore::CachedResource::resourceToRevalidate):

  • loader/cache/CachedResourceLoader.cpp:

(WebCore::CachedResourceLoader::determineRevalidationPolicy):

Reload on Vary mismatch.

  • platform/network/CacheValidation.cpp:

(WebCore::parseCacheControlDirectives):
(WebCore::headerValueForVary):
(WebCore::collectVaryingRequestHeaders):
(WebCore::verifyVaryingRequestHeaders):

Vary header collection and validation code moves here.

  • platform/network/CacheValidation.h:
Location:
trunk/Source/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r201799 r201800  
     12016-06-06  Antti Koivisto  <antti@apple.com>
     2
     3        WebKit memory cache doesn't respect Vary header
     4        https://bugs.webkit.org/show_bug.cgi?id=71509
     5        <rdar://problem/26651033>
     6
     7        Reviewed by Sam Weinig.
     8
     9        Implement Vary header support in WebCore memory cache.
     10
     11        The patch moves Vary header code from WebKit2 Network Cache to WebCore and uses it to
     12        verify the headers for CachedResources.
     13
     14        * loader/cache/CachedResource.cpp:
     15        (WebCore::CachedResource::failBeforeStarting):
     16        (WebCore::addAdditionalRequestHeadersToRequest):
     17
     18            Factor into standalone function so we can use it from varyHeaderValuesMatch.
     19
     20        (WebCore::CachedResource::addAdditionalRequestHeaders):
     21        (WebCore::CachedResource::load):
     22        (WebCore::CachedResource::setResponse):
     23
     24            Collect the Vary header values when we receive a response.
     25
     26        (WebCore::CachedResource::responseReceived):
     27        (WebCore::CachedResource::redirectChainAllowsReuse):
     28        (WebCore::CachedResource::varyHeaderValuesMatch):
     29
     30            Test for Vary match.
     31
     32        (WebCore::CachedResource::overheadSize):
     33        * loader/cache/CachedResource.h:
     34        (WebCore::CachedResource::isCacheValidator):
     35        (WebCore::CachedResource::resourceToRevalidate):
     36        * loader/cache/CachedResourceLoader.cpp:
     37        (WebCore::CachedResourceLoader::determineRevalidationPolicy):
     38
     39            Reload on Vary mismatch.
     40
     41        * platform/network/CacheValidation.cpp:
     42        (WebCore::parseCacheControlDirectives):
     43        (WebCore::headerValueForVary):
     44        (WebCore::collectVaryingRequestHeaders):
     45        (WebCore::verifyVaryingRequestHeaders):
     46
     47            Vary header collection and validation code moves here.
     48
     49        * platform/network/CacheValidation.h:
     50
    1512016-06-08  Myles C. Maxfield  <mmaxfield@apple.com>
    252
  • trunk/Source/WebCore/loader/cache/CachedResource.cpp

    r201596 r201800  
    183183}
    184184
    185 void CachedResource::addAdditionalRequestHeaders(CachedResourceLoader& cachedResourceLoader)
     185static void addAdditionalRequestHeadersToRequest(ResourceRequest& request, const CachedResourceLoader& cachedResourceLoader)
    186186{
    187187    // Note: We skip the Content-Security-Policy check here because we check
     
    192192    String outgoingReferrer;
    193193    String outgoingOrigin;
    194     if (m_resourceRequest.httpReferrer().isNull()) {
     194    if (request.httpReferrer().isNull()) {
    195195        outgoingReferrer = frameLoader.outgoingReferrer();
    196196        outgoingOrigin = frameLoader.outgoingOrigin();
    197197    } else {
    198         outgoingReferrer = m_resourceRequest.httpReferrer();
     198        outgoingReferrer = request.httpReferrer();
    199199        outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
    200200    }
    201201
    202     outgoingReferrer = SecurityPolicy::generateReferrerHeader(cachedResourceLoader.document()->referrerPolicy(), m_resourceRequest.url(), outgoingReferrer);
     202    auto referrerPolicy = cachedResourceLoader.document() ? cachedResourceLoader.document()->referrerPolicy() : ReferrerPolicy::Default;
     203    outgoingReferrer = SecurityPolicy::generateReferrerHeader(referrerPolicy, request.url(), outgoingReferrer);
    203204    if (outgoingReferrer.isEmpty())
    204         m_resourceRequest.clearHTTPReferrer();
     205        request.clearHTTPReferrer();
    205206    else
    206         m_resourceRequest.setHTTPReferrer(outgoingReferrer);
    207     FrameLoader::addHTTPOriginIfNeeded(m_resourceRequest, outgoingOrigin);
    208 
    209     frameLoader.addExtraFieldsToSubresourceRequest(m_resourceRequest);
     207        request.setHTTPReferrer(outgoingReferrer);
     208    FrameLoader::addHTTPOriginIfNeeded(request, outgoingOrigin);
     209
     210    frameLoader.addExtraFieldsToSubresourceRequest(request);
     211}
     212
     213void CachedResource::addAdditionalRequestHeaders(CachedResourceLoader& cachedResourceLoader)
     214{
     215    addAdditionalRequestHeadersToRequest(m_resourceRequest, cachedResourceLoader);
    210216}
    211217
     
    418424    m_response.setType(m_responseType);
    419425    m_response.setRedirected(m_redirectChainCacheStatus.status != RedirectChainCacheStatus::NoRedirection);
     426
     427    m_varyingHeaderValues = collectVaryingRequestHeaders(m_resourceRequest, m_response, m_sessionID);
    420428}
    421429
     
    766774}
    767775
     776bool CachedResource::varyHeaderValuesMatch(const ResourceRequest& request, const CachedResourceLoader& cachedResourceLoader)
     777{
     778    if (m_varyingHeaderValues.isEmpty())
     779        return true;
     780
     781    ResourceRequest requestWithFullHeaders(request);
     782    addAdditionalRequestHeadersToRequest(requestWithFullHeaders, cachedResourceLoader);
     783
     784    return verifyVaryingRequestHeaders(m_varyingHeaderValues, requestWithFullHeaders, m_sessionID);
     785}
     786
    768787unsigned CachedResource::overheadSize() const
    769788{
  • trunk/Source/WebCore/loader/cache/CachedResource.h

    r201324 r201800  
    243243    bool redirectChainAllowsReuse(ReuseExpiredRedirectionOrNot) const;
    244244
     245    bool varyHeaderValuesMatch(const ResourceRequest&, const CachedResourceLoader&);
     246
    245247    bool isCacheValidator() const { return m_resourceToRevalidate; }
    246248    CachedResource* resourceToRevalidate() const { return m_resourceToRevalidate; }
     
    355357    RedirectChainCacheStatus m_redirectChainCacheStatus;
    356358
     359    Vector<std::pair<String, String>> m_varyingHeaderValues;
     360
    357361    unsigned long m_identifierForLoadWithoutResourceLoader { 0 };
    358362};
  • trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp

    r201753 r201800  
    754754    }
    755755
     756    if (!existingResource->varyHeaderValuesMatch(request, *this))
     757        return Reload;
     758
    756759    auto* textDecoder = existingResource->textResourceDecoder();
    757760    if (textDecoder && !textDecoder->hasEqualEncodingForCharset(cachedResourceRequest.charset()))
  • trunk/Source/WebCore/platform/network/CacheValidation.cpp

    r195743 r201800  
    2828
    2929#include "HTTPHeaderMap.h"
     30#include "NetworkStorageSession.h"
     31#include "PlatformCookieJar.h"
     32#include "ResourceRequest.h"
    3033#include "ResourceResponse.h"
    3134#include <wtf/CurrentTime.h>
     
    327330}
    328331
    329 }
     332static String headerValueForVary(SessionID sessionID, const ResourceRequest& request, const String& headerName)
     333{
     334    // Explicit handling for cookies is needed because they are added magically by the networking layer.
     335    // FIXME: The value might have changed between making the request and retrieving the cookie here.
     336    // We could fetch the cookie when making the request but that seems overkill as the case is very rare and it
     337    // is a blocking operation. This should be sufficient to cover reasonable cases.
     338    if (headerName == httpHeaderNameString(HTTPHeaderName::Cookie)) {
     339        if (sessionID != SessionID::defaultSessionID()) {
     340            // FIXME: Don't know how to get the cookie. There should be a global way to get NetworkStorageSession from sessionID.
     341            return "";
     342        }
     343        return cookieRequestHeaderFieldValue(NetworkStorageSession::defaultStorageSession(), request.firstPartyForCookies(), request.url());
     344    }
     345    return request.httpHeaderField(headerName);
     346}
     347
     348Vector<std::pair<String, String>> collectVaryingRequestHeaders(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, SessionID sessionID)
     349{
     350    String varyValue = response.httpHeaderField(WebCore::HTTPHeaderName::Vary);
     351    if (varyValue.isEmpty())
     352        return { };
     353    Vector<String> varyingHeaderNames;
     354    varyValue.split(',', /*allowEmptyEntries*/ false, varyingHeaderNames);
     355    Vector<std::pair<String, String>> varyingRequestHeaders;
     356    varyingRequestHeaders.reserveCapacity(varyingHeaderNames.size());
     357    for (auto& varyHeaderName : varyingHeaderNames) {
     358        String headerName = varyHeaderName.stripWhiteSpace();
     359        String headerValue = headerValueForVary(sessionID, request, headerName);
     360        varyingRequestHeaders.append(std::make_pair(headerName, headerValue));
     361    }
     362    return varyingRequestHeaders;
     363}
     364
     365bool verifyVaryingRequestHeaders(const Vector<std::pair<String, String>>& varyingRequestHeaders, const WebCore::ResourceRequest& request, SessionID sessionID)
     366{
     367    for (auto& varyingRequestHeader : varyingRequestHeaders) {
     368        // FIXME: Vary: * in response would ideally trigger a cache delete instead of a store.
     369        if (varyingRequestHeader.first == "*")
     370            return false;
     371        if (sessionID != SessionID::defaultSessionID() && varyingRequestHeader.first == httpHeaderNameString(HTTPHeaderName::Cookie)) {
     372            // FIXME: See the comment in headerValueForVary.
     373            return false;
     374        }
     375        String headerValue = headerValueForVary(sessionID, request, varyingRequestHeader.first);
     376        if (headerValue != varyingRequestHeader.second)
     377            return false;
     378    }
     379    return true;
     380}
     381
     382}
  • trunk/Source/WebCore/platform/network/CacheValidation.h

    r196360 r201800  
    2828
    2929#include "PlatformExportMacros.h"
     30#include "SessionID.h"
    3031#include <wtf/Optional.h>
     32#include <wtf/Vector.h>
     33#include <wtf/text/WTFString.h>
    3134
    3235namespace WebCore {
    3336
    3437class HTTPHeaderMap;
     38class ResourceRequest;
    3539class ResourceResponse;
    3640
     
    6670WEBCORE_EXPORT CacheControlDirectives parseCacheControlDirectives(const HTTPHeaderMap&);
    6771
     72WEBCORE_EXPORT Vector<std::pair<String, String>> collectVaryingRequestHeaders(const ResourceRequest&, const ResourceResponse&, SessionID = SessionID::defaultSessionID());
     73WEBCORE_EXPORT bool verifyVaryingRequestHeaders(const Vector<std::pair<String, String>>& varyingRequestHeaders, const ResourceRequest&, SessionID = SessionID::defaultSessionID());
     74
    6875}
    6976
Note: See TracChangeset for help on using the changeset viewer.