Title: [207817] trunk/Source/WebCore
Revision
207817
Author
[email protected]
Date
2016-10-25 07:16:15 -0700 (Tue, 25 Oct 2016)

Log Message

CachedResourceLoader should set headers of the HTTP request prior checking for the cache
https://bugs.webkit.org/show_bug.cgi?id=163103

Patch by Youenn Fablet <[email protected]> on 2016-10-25
Reviewed by Darin Adler.

No expected change of behavior.

Moved referrer, user-agent, and origin headers setting to CachedResourceRequest/CachedResourceLoader before checking the cache.
This allows simplifying vary header checks and is more inline with the fetch specification.

To compute the referrer value, we need to know whether the request is cross-origin.
A helper function isRequestCrossOrigin is added for that purpose and is also used in CachedResource to set its initial response tainting.

We should disable setting user-agent and origin headers by FrameLoader for subresources since this is now done in CachedResourceLoader.
This could be done as a follow-up patch.

* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::CachedResource):
(WebCore::CachedResource::load):
(WebCore::CachedResource::varyHeaderValuesMatch):
(WebCore::addAdditionalRequestHeadersToRequest): Deleted.
(WebCore::CachedResource::addAdditionalRequestHeaders): Deleted.
* loader/cache/CachedResource.h:
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::updateHTTPRequestHeaders):
(WebCore::CachedResourceLoader::requestResource):
(WebCore::CachedResourceLoader::determineRevalidationPolicy):
* loader/cache/CachedResourceLoader.h:
* loader/cache/CachedResourceRequest.cpp:
(WebCore::CachedResourceRequest::updateForAccessControl):
(WebCore::CachedResourceRequest::updateReferrerOriginAndUserAgentHeaders):
(WebCore::isRequestCrossOrigin):
* loader/cache/CachedResourceRequest.h:
(WebCore::CachedResourceRequest::setOrigin):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (207816 => 207817)


--- trunk/Source/WebCore/ChangeLog	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/ChangeLog	2016-10-25 14:16:15 UTC (rev 207817)
@@ -1,3 +1,40 @@
+2016-10-25  Youenn Fablet  <[email protected]>
+
+        CachedResourceLoader should set headers of the HTTP request prior checking for the cache
+        https://bugs.webkit.org/show_bug.cgi?id=163103
+
+        Reviewed by Darin Adler.
+
+        No expected change of behavior.
+
+        Moved referrer, user-agent, and origin headers setting to CachedResourceRequest/CachedResourceLoader before checking the cache.
+        This allows simplifying vary header checks and is more inline with the fetch specification.
+
+        To compute the referrer value, we need to know whether the request is cross-origin.
+        A helper function isRequestCrossOrigin is added for that purpose and is also used in CachedResource to set its initial response tainting.
+
+        We should disable setting user-agent and origin headers by FrameLoader for subresources since this is now done in CachedResourceLoader.
+        This could be done as a follow-up patch.
+
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::CachedResource):
+        (WebCore::CachedResource::load):
+        (WebCore::CachedResource::varyHeaderValuesMatch):
+        (WebCore::addAdditionalRequestHeadersToRequest): Deleted.
+        (WebCore::CachedResource::addAdditionalRequestHeaders): Deleted.
+        * loader/cache/CachedResource.h:
+        * loader/cache/CachedResourceLoader.cpp:
+        (WebCore::CachedResourceLoader::updateHTTPRequestHeaders):
+        (WebCore::CachedResourceLoader::requestResource):
+        (WebCore::CachedResourceLoader::determineRevalidationPolicy):
+        * loader/cache/CachedResourceLoader.h:
+        * loader/cache/CachedResourceRequest.cpp:
+        (WebCore::CachedResourceRequest::updateForAccessControl):
+        (WebCore::CachedResourceRequest::updateReferrerOriginAndUserAgentHeaders):
+        (WebCore::isRequestCrossOrigin):
+        * loader/cache/CachedResourceRequest.h:
+        (WebCore::CachedResourceRequest::setOrigin):
+
 2016-10-25  Andreas Kling  <[email protected]>
 
         More PassRefPtr purging in WebCore.

Modified: trunk/Source/WebCore/loader/cache/CachedResource.cpp (207816 => 207817)


--- trunk/Source/WebCore/loader/cache/CachedResource.cpp	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/loader/cache/CachedResource.cpp	2016-10-25 14:16:15 UTC (rev 207817)
@@ -47,7 +47,6 @@
 #include "ResourceHandle.h"
 #include "SchemeRegistry.h"
 #include "SecurityOrigin.h"
-#include "SecurityPolicy.h"
 #include "SubresourceLoader.h"
 #include <wtf/CurrentTime.h>
 #include <wtf/MathExtras.h>
@@ -135,9 +134,7 @@
     // FIXME: We should have a better way of checking for Navigation loads, maybe FetchMode::Options::Navigate.
     ASSERT(m_origin || m_type == CachedResource::MainResource);
 
-    if (m_options.mode != FetchOptions::Mode::SameOrigin && m_origin
-        && !(m_resourceRequest.url().protocolIsData() && m_options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set)
-        && !m_origin->canRequest(m_resourceRequest.url()))
+    if (isRequestCrossOrigin(m_origin.get(), m_resourceRequest.url(), m_options))
         setCrossOrigin();
 }
 
@@ -183,66 +180,6 @@
     error(CachedResource::LoadError);
 }
 
-static void addAdditionalRequestHeadersToRequest(ResourceRequest& request, const CachedResourceLoader& cachedResourceLoader, CachedResource& resource)
-{
-    if (resource.type() == CachedResource::MainResource)
-        return;
-    // In some cases we may try to load resources in frameless documents. Such loads always fail.
-    // FIXME: We shouldn't get this far.
-    if (!cachedResourceLoader.frame())
-        return;
-
-    // Note: We skip the Content-Security-Policy check here because we check
-    // the Content-Security-Policy at the CachedResourceLoader layer so we can
-    // handle different resource types differently.
-    FrameLoader& frameLoader = cachedResourceLoader.frame()->loader();
-    String outgoingReferrer;
-    String outgoingOrigin;
-    if (request.httpReferrer().isNull()) {
-        outgoingReferrer = frameLoader.outgoingReferrer();
-        outgoingOrigin = frameLoader.outgoingOrigin();
-    } else {
-        outgoingReferrer = request.httpReferrer();
-        outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
-    }
-
-    // FIXME: Refactor SecurityPolicy::generateReferrerHeader to align with new terminology used in https://w3c.github.io/webappsec-referrer-policy.
-    switch (resource.options().referrerPolicy) {
-    case FetchOptions::ReferrerPolicy::EmptyString: {
-        ReferrerPolicy referrerPolicy = cachedResourceLoader.document() ? cachedResourceLoader.document()->referrerPolicy() : ReferrerPolicy::Default;
-        outgoingReferrer = SecurityPolicy::generateReferrerHeader(referrerPolicy, request.url(), outgoingReferrer);
-        break; }
-    case FetchOptions::ReferrerPolicy::NoReferrerWhenDowngrade:
-        outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Default, request.url(), outgoingReferrer);
-        break;
-    case FetchOptions::ReferrerPolicy::NoReferrer:
-        outgoingReferrer = String();
-        break;
-    case FetchOptions::ReferrerPolicy::Origin:
-        outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Origin, request.url(), outgoingReferrer);
-        break;
-    case FetchOptions::ReferrerPolicy::OriginWhenCrossOrigin:
-        if (resource.isCrossOrigin())
-            outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Origin, request.url(), outgoingReferrer);
-        break;
-    case FetchOptions::ReferrerPolicy::UnsafeUrl:
-        break;
-    };
-
-    if (outgoingReferrer.isEmpty())
-        request.clearHTTPReferrer();
-    else
-        request.setHTTPReferrer(outgoingReferrer);
-    FrameLoader::addHTTPOriginIfNeeded(request, outgoingOrigin);
-
-    frameLoader.addExtraFieldsToSubresourceRequest(request);
-}
-
-void CachedResource::addAdditionalRequestHeaders(CachedResourceLoader& loader)
-{
-    addAdditionalRequestHeadersToRequest(m_resourceRequest, loader, *this);
-}
-
 void CachedResource::load(CachedResourceLoader& cachedResourceLoader)
 {
     if (!cachedResourceLoader.frame()) {
@@ -311,8 +248,12 @@
 #endif
     m_resourceRequest.setPriority(loadPriority());
 
-    addAdditionalRequestHeaders(cachedResourceLoader);
+    // Navigation algorithm is setting up the request before sending it to CachedResourceLoader?CachedResource.
+    // So no need for extra fields for MainResource.
+    if (type() != CachedResource::MainResource)
+        frameLoader.addExtraFieldsToSubresourceRequest(m_resourceRequest);
 
+
     // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers.
     // We should look into removing the expectation of that knowledge from the platform network stacks.
     ResourceRequest request(m_resourceRequest);
@@ -835,15 +776,12 @@
     return WebCore::redirectChainAllowsReuse(m_redirectChainCacheStatus, reuseExpiredRedirection);
 }
 
-bool CachedResource::varyHeaderValuesMatch(const ResourceRequest& request, const CachedResourceLoader& cachedResourceLoader)
+bool CachedResource::varyHeaderValuesMatch(const ResourceRequest& request)
 {
     if (m_varyingHeaderValues.isEmpty())
         return true;
 
-    ResourceRequest requestWithFullHeaders(request);
-    addAdditionalRequestHeadersToRequest(requestWithFullHeaders, cachedResourceLoader, *this);
-
-    return verifyVaryingRequestHeaders(m_varyingHeaderValues, requestWithFullHeaders, m_sessionID);
+    return verifyVaryingRequestHeaders(m_varyingHeaderValues, request, m_sessionID);
 }
 
 unsigned CachedResource::overheadSize() const

Modified: trunk/Source/WebCore/loader/cache/CachedResource.h (207816 => 207817)


--- trunk/Source/WebCore/loader/cache/CachedResource.h	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/loader/cache/CachedResource.h	2016-10-25 14:16:15 UTC (rev 207817)
@@ -233,8 +233,8 @@
     void increasePreloadCount() { ++m_preloadCount; }
     void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
 
-    void registerHandle(CachedResourceHandleBase* h);
-    WEBCORE_EXPORT void unregisterHandle(CachedResourceHandleBase* h);
+    void registerHandle(CachedResourceHandleBase*);
+    WEBCORE_EXPORT void unregisterHandle(CachedResourceHandleBase*);
 
     bool canUseCacheValidator() const;
 
@@ -243,7 +243,7 @@
     bool redirectChainAllowsReuse(ReuseExpiredRedirectionOrNot) const;
     bool hasRedirections() const { return m_redirectChainCacheStatus.status != RedirectChainCacheStatus::Status::NoRedirection;  }
 
-    bool varyHeaderValuesMatch(const ResourceRequest&, const CachedResourceLoader&);
+    bool varyHeaderValuesMatch(const ResourceRequest&);
 
     bool isCacheValidator() const { return m_resourceToRevalidate; }
     CachedResource* resourceToRevalidate() const { return m_resourceToRevalidate; }

Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp (207816 => 207817)


--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp	2016-10-25 14:16:15 UTC (rev 207817)
@@ -65,6 +65,7 @@
 #include "RuntimeEnabledFeatures.h"
 #include "ScriptController.h"
 #include "SecurityOrigin.h"
+#include "SecurityPolicy.h"
 #include "SessionID.h"
 #include "Settings.h"
 #include "StyleSheetContents.h"
@@ -662,10 +663,18 @@
     // FIXME: Decide whether to support client hints
 }
 
+void CachedResourceLoader::updateHTTPRequestHeaders(CachedResource::Type type, CachedResourceRequest& request)
+{
+    // Implementing steps 7 to 12 of https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
 
-void CachedResourceLoader::updateHTTPRequestHeaders(CachedResourceRequest& request)
-{
-    // Implementing steps 10 to 12 of https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
+    // FIXME: We should reconcile handling of MainResource with other resources.
+    if (type != CachedResource::Type::MainResource) {
+        // In some cases we may try to load resources in frameless documents. Such loads always fail.
+        // FIXME: We shouldn't need to do the check on frame.
+        if (auto* frame = this->frame())
+            request.updateReferrerOriginAndUserAgentHeaders(frame->loader(), document() ? document()->referrerPolicy() : ReferrerPolicy::Default);
+    }
+
     request.updateAccordingCacheMode();
 }
 
@@ -724,7 +733,7 @@
 #endif
 
     if (request.resourceRequest().url().protocolIsInHTTPFamily())
-        updateHTTPRequestHeaders(request);
+        updateHTTPRequestHeaders(type, request);
 
     auto& memoryCache = MemoryCache::singleton();
     if (request.allowsCaching() && memoryCache.disabled()) {
@@ -921,7 +930,7 @@
         return Reload;
     }
 
-    if (!existingResource->varyHeaderValuesMatch(request, *this))
+    if (!existingResource->varyHeaderValuesMatch(request))
         return Reload;
 
     auto* textDecoder = existingResource->textResourceDecoder();

Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.h (207816 => 207817)


--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.h	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.h	2016-10-25 14:16:15 UTC (rev 207817)
@@ -154,13 +154,15 @@
     enum class ForPreload { Yes, No };
     enum class DeferOption { NoDefer, DeferredByClient };
 
-    void updateHTTPRequestHeaders(CachedResourceRequest&);
     CachedResourceHandle<CachedResource> requestResource(CachedResource::Type, CachedResourceRequest&&, ForPreload = ForPreload::No, DeferOption = DeferOption::NoDefer);
-    void prepareFetch(CachedResource::Type, CachedResourceRequest&);
     CachedResourceHandle<CachedResource> revalidateResource(CachedResourceRequest&&, CachedResource&);
     CachedResourceHandle<CachedResource> loadResource(CachedResource::Type, CachedResourceRequest&&);
     CachedResourceHandle<CachedResource> requestPreload(CachedResource::Type, CachedResourceRequest&&);
 
+    void prepareFetch(CachedResource::Type, CachedResourceRequest&);
+    void updateHTTPRequestHeaders(CachedResource::Type, CachedResourceRequest&);
+    void updateReferrerOriginAndUserAgentHeaders(CachedResourceRequest&);
+
     bool canRequest(CachedResource::Type, const URL&, const CachedResourceRequest&, ForPreload);
 
     enum RevalidationPolicy { Use, Revalidate, Reload, Load };

Modified: trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp (207816 => 207817)


--- trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp	2016-10-25 14:16:15 UTC (rev 207817)
@@ -31,8 +31,10 @@
 #include "CrossOriginAccessControl.h"
 #include "Document.h"
 #include "Element.h"
+#include "FrameLoader.h"
 #include "HTTPHeaderValues.h"
 #include "MemoryCache.h"
+#include "SecurityPolicy.h"
 #include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
@@ -102,7 +104,7 @@
     ASSERT(document.securityOrigin());
 
     m_origin = document.securityOrigin();
-    WebCore::updateRequestForAccessControl(m_resourceRequest, *document.securityOrigin(), m_options.allowCredentials);
+    WebCore::updateRequestForAccessControl(m_resourceRequest, *m_origin, m_options.allowCredentials);
 }
 
 void upgradeInsecureResourceRequestIfNeeded(ResourceRequest& request, Document& document)
@@ -209,4 +211,64 @@
 }
 #endif
 
+void CachedResourceRequest::updateReferrerOriginAndUserAgentHeaders(FrameLoader& frameLoader, ReferrerPolicy defaultPolicy)
+{
+    // Implementing step 7 to 9 of https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
+
+    String outgoingOrigin;
+    String outgoingReferrer = m_resourceRequest.httpReferrer();
+    if (!outgoingReferrer.isNull())
+        outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
+    else {
+        outgoingReferrer = frameLoader.outgoingReferrer();
+        outgoingOrigin = frameLoader.outgoingOrigin();
+    }
+
+    // FIXME: Refactor SecurityPolicy::generateReferrerHeader to align with new terminology used in https://w3c.github.io/webappsec-referrer-policy.
+    switch (m_options.referrerPolicy) {
+    case FetchOptions::ReferrerPolicy::EmptyString: {
+        outgoingReferrer = SecurityPolicy::generateReferrerHeader(defaultPolicy, m_resourceRequest.url(), outgoingReferrer);
+        break; }
+    case FetchOptions::ReferrerPolicy::NoReferrerWhenDowngrade:
+        outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Default, m_resourceRequest.url(), outgoingReferrer);
+        break;
+    case FetchOptions::ReferrerPolicy::NoReferrer:
+        outgoingReferrer = String();
+        break;
+    case FetchOptions::ReferrerPolicy::Origin:
+        outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Origin, m_resourceRequest.url(), outgoingReferrer);
+        break;
+    case FetchOptions::ReferrerPolicy::OriginWhenCrossOrigin:
+        if (isRequestCrossOrigin(m_origin.get(), m_resourceRequest.url(), m_options))
+            outgoingReferrer = SecurityPolicy::generateReferrerHeader(ReferrerPolicy::Origin, m_resourceRequest.url(), outgoingReferrer);
+        break;
+    case FetchOptions::ReferrerPolicy::UnsafeUrl:
+        break;
+    };
+
+    if (outgoingReferrer.isEmpty())
+        m_resourceRequest.clearHTTPReferrer();
+    else
+        m_resourceRequest.setHTTPReferrer(outgoingReferrer);
+    FrameLoader::addHTTPOriginIfNeeded(m_resourceRequest, outgoingOrigin);
+
+    frameLoader.applyUserAgent(m_resourceRequest);
+}
+
+bool isRequestCrossOrigin(SecurityOrigin* origin, const URL& requestURL, const ResourceLoaderOptions& options)
+{
+    if (!origin)
+        return false;
+
+    // Using same origin mode guarantees the loader will not do a cross-origin load, so we let it take care of it and just return false.
+    if (options.mode == FetchOptions::Mode::SameOrigin)
+        return false;
+
+    // FIXME: We should remove options.sameOriginDataURLFlag once https://github.com/whatwg/fetch/issues/393 is fixed.
+    if (requestURL.protocolIsData() && options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set)
+        return false;
+
+    return !origin->canRequest(requestURL);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/cache/CachedResourceRequest.h (207816 => 207817)


--- trunk/Source/WebCore/loader/cache/CachedResourceRequest.h	2016-10-25 12:16:26 UTC (rev 207816)
+++ trunk/Source/WebCore/loader/cache/CachedResourceRequest.h	2016-10-25 14:16:15 UTC (rev 207817)
@@ -41,8 +41,13 @@
 namespace ContentExtensions {
 struct BlockedStatus;
 }
+
 class Document;
+class FrameLoader;
+enum class ReferrerPolicy;
 
+bool isRequestCrossOrigin(SecurityOrigin*, const URL& requestURL, const ResourceLoaderOptions&);
+
 class CachedResourceRequest {
 public:
     CachedResourceRequest(ResourceRequest&&, const ResourceLoaderOptions&, Optional<ResourceLoadPriority> = Nullopt, String&& charset = String());
@@ -63,6 +68,7 @@
     void setAsPotentiallyCrossOrigin(const String&, Document&);
     void updateForAccessControl(Document&);
 
+    void updateReferrerOriginAndUserAgentHeaders(FrameLoader&, ReferrerPolicy);
     void upgradeInsecureRequestIfNeeded(Document&);
     void setAcceptHeaderIfNone(CachedResource::Type);
     void updateAccordingCacheMode();
@@ -74,7 +80,7 @@
     void setDomainForCachePartition(Document&);
 #endif
 
-    void setOrigin(RefPtr<SecurityOrigin>&& origin) { ASSERT(!m_origin); m_origin = WTFMove(origin); }
+    void setOrigin(RefPtr<SecurityOrigin>&& origin) { m_origin = WTFMove(origin); }
     RefPtr<SecurityOrigin> releaseOrigin() { return WTFMove(m_origin); }
     SecurityOrigin* origin() const { return m_origin.get(); }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to