Add a reload policy where only expired subresources are revalidated
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Mar 2017 19:52:49 +0000 (19:52 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Mar 2017 19:52:49 +0000 (19:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169756

Reviewed by Andreas Kling.

Source/WebCore:

Test: http/tests/cache/reload-expired-only.html

The default reload behavior revalidates all resources on the page. This patch adds
a new policy that revalidates expired (and uncacheable) resources only. Using this
policy can speed up reloads significantly and also reduce network traffic and server
load.

* history/PageCache.cpp:
(WebCore::canCachePage):
* inspector/InspectorPageAgent.cpp:
(WebCore::InspectorPageAgent::reload):
* loader/FrameLoader.cpp:
(WebCore::isBackForwardLoadType):
(WebCore::isReload):

    Add a helper function.

(WebCore::FrameLoader::loadURL):
(WebCore::logNavigation):
(WebCore::FrameLoader::reload):

    Replace bool arguments with OptionSet<ReloadOption>. Most of the patch is about adapting to this.

(WebCore::FrameLoader::transitionToCommitted):
(WebCore::FrameLoader::subresourceCachePolicy):

    Return CachePolicyVerify for 'ReloadExpiredOnly' frame load type. This is the substantive
    change that causes the behavior difference.

(WebCore::FrameLoader::checkLoadCompleteForThisFrame):
(WebCore::FrameLoader::defaultRequestCachingPolicy):

    Flip the isMainResource condition for better readability.

(WebCore::FrameLoader::shouldPerformFragmentNavigation):
(WebCore::FrameLoader::loadDifferentDocumentItem):
* loader/FrameLoader.h:
(WebCore::FrameLoader::reload):
* loader/FrameLoaderTypes.h:
* loader/HistoryController.cpp:
(WebCore::HistoryController::restoreDocumentState):
* page/DiagnosticLoggingKeys.cpp:
(WebCore::DiagnosticLoggingKeys::reloadRevalidatingExpiredKey):
* page/DiagnosticLoggingKeys.h:
* replay/UserInputBridge.cpp:
(WebCore::UserInputBridge::reloadFrame):
* replay/UserInputBridge.h:
* testing/Internals.cpp:
(WebCore::Internals::forceReload):
(WebCore::Internals::reloadExpiredOnly):

    Testing support.

* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit/mac:

* WebView/WebFrame.mm:
(toWebFrameLoadType):
(-[WebFrame reload]):
(-[WebFrame reloadFromOrigin]):

Source/WebKit2:

* UIProcess/API/C/WKPage.cpp:
(WKPageReload):
(WKPageReloadWithoutContentBlockers):
(WKPageReloadFromOrigin):
(WKPageReloadExpiredOnly):
* UIProcess/API/C/WKPage.h:
* UIProcess/API/Cocoa/WKBrowsingContextController.mm:
(-[WKBrowsingContextController reload]):
(-[WKBrowsingContextController reloadFromOrigin]):
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView reload]):
(-[WKWebView reloadFromOrigin]):
(-[WKWebView _reloadWithoutContentBlockers]):
(-[WKWebView _reloadExpiredOnly]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::reloadBrowsingContext):
* UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::didHandleContentFilterUnblockNavigation):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::reload):
* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::reload):
(WebKit::shouldReuseCommittedSandboxExtension):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

LayoutTests:

* http/tests/cache/reload-expired-only-expected.txt: Added.
* http/tests/cache/reload-expired-only.html: Added.
* http/tests/cache/resources/document-with-cached-unique-script.html: Added.
* http/tests/cache/resources/random-cached.cgi:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@214113 268f45cc-cd09-0410-ab3c-d52691b4dbfc

36 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/cache/reload-expired-only-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/cache/reload-expired-only.html [new file with mode: 0644]
LayoutTests/http/tests/cache/resources/document-with-cached-unique-script.html [new file with mode: 0644]
LayoutTests/http/tests/cache/resources/random-cached.cgi
Source/WebCore/ChangeLog
Source/WebCore/history/PageCache.cpp
Source/WebCore/inspector/InspectorPageAgent.cpp
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/FrameLoader.h
Source/WebCore/loader/FrameLoaderTypes.h
Source/WebCore/loader/HistoryController.cpp
Source/WebCore/page/DiagnosticLoggingKeys.cpp
Source/WebCore/page/DiagnosticLoggingKeys.h
Source/WebCore/replay/UserInputBridge.cpp
Source/WebCore/replay/UserInputBridge.h
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebFrame.mm
Source/WebKit/win/WebFrame.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/C/WKPage.cpp
Source/WebKit2/UIProcess/API/C/WKPage.h
Source/WebKit2/UIProcess/API/Cocoa/WKBrowsingContextController.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp
Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp
Source/WebKit2/UIProcess/WebFrameProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in

index daa0f20..6247bca 100644 (file)
@@ -1,3 +1,15 @@
+2017-03-17  Antti Koivisto  <antti@apple.com>
+
+        Add a reload policy where only expired subresources are revalidated
+        https://bugs.webkit.org/show_bug.cgi?id=169756
+
+        Reviewed by Andreas Kling.
+
+        * http/tests/cache/reload-expired-only-expected.txt: Added.
+        * http/tests/cache/reload-expired-only.html: Added.
+        * http/tests/cache/resources/document-with-cached-unique-script.html: Added.
+        * http/tests/cache/resources/random-cached.cgi:
+
 2017-03-17  Nan Wang  <n_wang@apple.com>
 
         AX: VoiceOver no longer works corectly with editable text in the web
diff --git a/LayoutTests/http/tests/cache/reload-expired-only-expected.txt b/LayoutTests/http/tests/cache/reload-expired-only-expected.txt
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
diff --git a/LayoutTests/http/tests/cache/reload-expired-only.html b/LayoutTests/http/tests/cache/reload-expired-only.html
new file mode 100644 (file)
index 0000000..dc02861
--- /dev/null
@@ -0,0 +1,27 @@
+<body>
+<script>
+if (testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.waitUntilDone();
+}
+const testWindow = window.open('http://127.0.0.1:8000/cache/resources/document-with-cached-unique-script.html');
+
+var firstNumber;
+window.addEventListener("message", (event) => {
+    if (firstNumber) {
+        const secondNumber = event.data;
+        if (firstNumber == secondNumber)
+            document.body.innerHTML = "PASS";
+        else
+            document.body.innerHTML = `FAIL: firstNumber={$firstNumber} secondNumber={$secondNumber}`;
+        if (testRunner)
+            testRunner.notifyDone();
+        return;
+    }
+    firstNumber = event.data;
+    if (testWindow.internals)
+        testWindow.internals.reloadExpiredOnly();
+});
+
+</script>
diff --git a/LayoutTests/http/tests/cache/resources/document-with-cached-unique-script.html b/LayoutTests/http/tests/cache/resources/document-with-cached-unique-script.html
new file mode 100644 (file)
index 0000000..fd7bd08
--- /dev/null
@@ -0,0 +1,5 @@
+<h1></h1>
+<script src='random-cached.cgi'></script>
+<script>
+window.opener.postMessage(randomNumber, '*');
+</script>
index eb49be7..3ed1be9 100755 (executable)
@@ -2,7 +2,6 @@
 
 print "Content-type: text/javascript\n";
 print "Cache-control: max-age=60000\n";
-print "ETag: \"123456789\"\n";
 print "\n";
 
 my $random_number = int(rand(1000000000000));
index 018de53..0dccad8 100644 (file)
@@ -1,3 +1,66 @@
+2017-03-17  Antti Koivisto  <antti@apple.com>
+
+        Add a reload policy where only expired subresources are revalidated
+        https://bugs.webkit.org/show_bug.cgi?id=169756
+
+        Reviewed by Andreas Kling.
+
+        Test: http/tests/cache/reload-expired-only.html
+
+        The default reload behavior revalidates all resources on the page. This patch adds
+        a new policy that revalidates expired (and uncacheable) resources only. Using this
+        policy can speed up reloads significantly and also reduce network traffic and server
+        load.
+
+        * history/PageCache.cpp:
+        (WebCore::canCachePage):
+        * inspector/InspectorPageAgent.cpp:
+        (WebCore::InspectorPageAgent::reload):
+        * loader/FrameLoader.cpp:
+        (WebCore::isBackForwardLoadType):
+        (WebCore::isReload):
+
+            Add a helper function.
+
+        (WebCore::FrameLoader::loadURL):
+        (WebCore::logNavigation):
+        (WebCore::FrameLoader::reload):
+
+            Replace bool arguments with OptionSet<ReloadOption>. Most of the patch is about adapting to this.
+
+        (WebCore::FrameLoader::transitionToCommitted):
+        (WebCore::FrameLoader::subresourceCachePolicy):
+
+            Return CachePolicyVerify for 'ReloadExpiredOnly' frame load type. This is the substantive
+            change that causes the behavior difference.
+
+        (WebCore::FrameLoader::checkLoadCompleteForThisFrame):
+        (WebCore::FrameLoader::defaultRequestCachingPolicy):
+
+            Flip the isMainResource condition for better readability.
+
+        (WebCore::FrameLoader::shouldPerformFragmentNavigation):
+        (WebCore::FrameLoader::loadDifferentDocumentItem):
+        * loader/FrameLoader.h:
+        (WebCore::FrameLoader::reload):
+        * loader/FrameLoaderTypes.h:
+        * loader/HistoryController.cpp:
+        (WebCore::HistoryController::restoreDocumentState):
+        * page/DiagnosticLoggingKeys.cpp:
+        (WebCore::DiagnosticLoggingKeys::reloadRevalidatingExpiredKey):
+        * page/DiagnosticLoggingKeys.h:
+        * replay/UserInputBridge.cpp:
+        (WebCore::UserInputBridge::reloadFrame):
+        * replay/UserInputBridge.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::forceReload):
+        (WebCore::Internals::reloadExpiredOnly):
+
+            Testing support.
+
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-03-17  Nan Wang  <n_wang@apple.com>
 
         AX: VoiceOver no longer works corectly with editable text in the web
index ba7e066..abb03ff 100644 (file)
@@ -249,6 +249,13 @@ static bool canCachePage(Page& page)
         isCacheable = false;
         break;
     }
+    case FrameLoadType::ReloadExpiredOnly: {
+        // No point writing to the cache on a reload, since we will just write over it again when we leave that page.
+        PCLOG("   -Load type is: ReloadRevalidatingExpired");
+        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::reloadRevalidatingExpiredKey());
+        isCacheable = false;
+        break;
+    }
     case FrameLoadType::Standard:
     case FrameLoadType::Back:
     case FrameLoadType::Forward:
index de057b5..32fd47e 100644 (file)
@@ -423,7 +423,11 @@ void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString& error, const
 void InspectorPageAgent::reload(ErrorString&, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
 {
     m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : emptyString();
-    m_page.mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
+
+    OptionSet<ReloadOption> reloadOptions;
+    if (optionalIgnoreCache && *optionalIgnoreCache)
+        reloadOptions |= ReloadOption::FromOrigin;
+    m_page.mainFrame().loader().reload(reloadOptions);
 }
 
 void InspectorPageAgent::navigate(ErrorString&, const String& url)
index 61cc2e9..f9937c7 100644 (file)
@@ -156,6 +156,7 @@ bool isBackForwardLoadType(FrameLoadType type)
     case FrameLoadType::Standard:
     case FrameLoadType::Reload:
     case FrameLoadType::ReloadFromOrigin:
+    case FrameLoadType::ReloadExpiredOnly:
     case FrameLoadType::Same:
     case FrameLoadType::RedirectWithLockedBackForwardList:
     case FrameLoadType::Replace:
@@ -169,6 +170,26 @@ bool isBackForwardLoadType(FrameLoadType type)
     return false;
 }
 
+bool isReload(FrameLoadType type)
+{
+    switch (type) {
+    case FrameLoadType::Reload:
+    case FrameLoadType::ReloadFromOrigin:
+    case FrameLoadType::ReloadExpiredOnly:
+        return true;
+    case FrameLoadType::Standard:
+    case FrameLoadType::Same:
+    case FrameLoadType::RedirectWithLockedBackForwardList:
+    case FrameLoadType::Replace:
+    case FrameLoadType::Back:
+    case FrameLoadType::Forward:
+    case FrameLoadType::IndexedBackForward:
+        return false;
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
 // This is not in the FrameLoader class to emphasize that it does not depend on
 // private FrameLoader data, and to avoid increasing the number of public functions
 // with access to private data.  Since only this .cpp file needs it, making it
@@ -1213,7 +1234,7 @@ void FrameLoader::loadURL(const FrameLoadRequest& frameLoadRequest, const String
         request.setDomainForCachePartition(m_frame.tree().top().document()->securityOrigin().domainForCachePartition());
 
     addExtraFieldsToRequest(request, newLoadType, true);
-    if (newLoadType == FrameLoadType::Reload || newLoadType == FrameLoadType::ReloadFromOrigin)
+    if (isReload(newLoadType))
         request.setCachePolicy(ReloadIgnoringCacheData);
 
     ASSERT(newLoadType != FrameLoadType::Same);
@@ -1266,7 +1287,7 @@ void FrameLoader::loadURL(const FrameLoadRequest& frameLoadRequest, const String
         m_quickRedirectComing = false;
         if (m_provisionalDocumentLoader)
             m_provisionalDocumentLoader->setIsClientRedirect(true);
-    } else if (sameURL && newLoadType != FrameLoadType::Reload && newLoadType != FrameLoadType::ReloadFromOrigin) {
+    } else if (sameURL && !isReload(newLoadType)) {
         // Example of this case are sites that reload the same URL with a different cookie
         // driving the generated content, or a master frame with links that drive a target
         // frame, where the user has clicked on the same link repeatedly.
@@ -1404,6 +1425,9 @@ static void logNavigation(MainFrame& frame, const URL& destinationURL, FrameLoad
     case FrameLoadType::ReloadFromOrigin:
         navigationDescription = ASCIILiteral("reloadFromOrigin");
         break;
+    case FrameLoadType::ReloadExpiredOnly:
+        navigationDescription = ASCIILiteral("reloadRevalidatingExpired");
+        break;
     case FrameLoadType::Replace:
     case FrameLoadType::RedirectWithLockedBackForwardList:
         // Not logging those for now.
@@ -1576,7 +1600,7 @@ void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
     loadWithDocumentLoader(loader.ptr(), FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
 }
 
-void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled)
+void FrameLoader::reload(OptionSet<ReloadOption> options)
 {
     if (!m_documentLoader)
         return;
@@ -1597,7 +1621,7 @@ void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled)
     Ref<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
     applyShouldOpenExternalURLsPolicyToNewDocumentLoader(loader, m_documentLoader->shouldOpenExternalURLsPolicyToPropagate());
 
-    loader->setUserContentExtensionsEnabled(contentBlockersEnabled);
+    loader->setUserContentExtensionsEnabled(!options.contains(ReloadOption::DisableContentBlockers));
     
     ResourceRequest& request = loader->request();
 
@@ -1609,8 +1633,16 @@ void FrameLoader::reload(bool endToEndReload, bool contentBlockersEnabled)
         loader->setTriggeringAction(NavigationAction(request, NavigationType::FormResubmitted));
 
     loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
+
+    auto frameLoadTypeForReloadOptions = [] (auto options) {
+        if (options.contains(ReloadOption::FromOrigin))
+            return FrameLoadType::ReloadFromOrigin;
+        if (options.contains(ReloadOption::ExpiredOnly))
+            return FrameLoadType::ReloadExpiredOnly;
+        return FrameLoadType::Reload;
+    };
     
-    loadWithDocumentLoader(loader.ptr(), endToEndReload ? FrameLoadType::ReloadFromOrigin : FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
+    loadWithDocumentLoader(loader.ptr(), frameLoadTypeForReloadOptions(options), 0, AllowNavigationToInvalidURL::Yes);
 }
 
 void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
@@ -1972,6 +2004,7 @@ void FrameLoader::transitionToCommitted(CachedPage* cachedPage)
 
     case FrameLoadType::Reload:
     case FrameLoadType::ReloadFromOrigin:
+    case FrameLoadType::ReloadExpiredOnly:
     case FrameLoadType::Same:
     case FrameLoadType::Replace:
         history().updateForReload();
@@ -1989,11 +2022,6 @@ void FrameLoader::transitionToCommitted(CachedPage* cachedPage)
         history().updateForRedirectWithLockedBackForwardList();
         m_client.transitionToCommittedForNewPage();
         break;
-
-    // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
-    // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
-    default:
-        ASSERT_NOT_REACHED();
     }
 
     m_documentLoader->writer().setMIMEType(dl->responseMIMEType());
@@ -2229,6 +2257,7 @@ CachePolicy FrameLoader::subresourceCachePolicy() const
     case FrameLoadType::Replace:
     case FrameLoadType::Same:
     case FrameLoadType::Standard:
+    case FrameLoadType::ReloadExpiredOnly:
         return CachePolicyVerify;
     }
 
@@ -2315,7 +2344,7 @@ void FrameLoader::checkLoadCompleteForThisFrame()
              
             // If the user had a scroll point, scroll to it, overriding the anchor point if any.
             if (m_frame.page()) {
-                if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadType::Reload || m_loadType == FrameLoadType::ReloadFromOrigin)
+                if (isBackForwardLoadType(m_loadType) || isReload(m_loadType))
                     history().restoreScrollPositionAndViewState();
             }
 
@@ -2613,27 +2642,31 @@ ResourceRequestCachePolicy FrameLoader::defaultRequestCachingPolicy(const Resour
 {
     if (m_overrideCachePolicyForTesting)
         return m_overrideCachePolicyForTesting.value();
-    if (!isMainResource) {
-        if (request.isConditional())
+
+    if (isMainResource) {
+        if (isReload(loadType) || request.isConditional())
             return ReloadIgnoringCacheData;
-        if (documentLoader()->isLoadingInAPISense()) {
-            // If we inherit cache policy from a main resource, we use the DocumentLoader's
-            // original request cache policy for two reasons:
-            // 1. For POST requests, we mutate the cache policy for the main resource,
-            //    but we do not want this to apply to subresources
-            // 2. Delegates that modify the cache policy using willSendRequest: should
-            //    not affect any other resources. Such changes need to be done
-            //    per request.
-            ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
-            // Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails.
-            // This policy is set on initial request too, but should not be inherited.
-            return (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
-        }
-    // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading.
-    // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest().
-    } else if (loadType == FrameLoadType::Reload || loadType == FrameLoadType::ReloadFromOrigin || request.isConditional())
+
+        return UseProtocolCachePolicy;
+    }
+
+    if (request.isConditional())
         return ReloadIgnoringCacheData;
 
+    if (documentLoader()->isLoadingInAPISense()) {
+        // If we inherit cache policy from a main resource, we use the DocumentLoader's
+        // original request cache policy for two reasons:
+        // 1. For POST requests, we mutate the cache policy for the main resource,
+        //    but we do not want this to apply to subresources
+        // 2. Delegates that modify the cache policy using willSendRequest: should
+        //    not affect any other resources. Such changes need to be done
+        //    per request.
+        ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
+        // Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails.
+        // This policy is set on initial request too, but should not be inherited.
+        return (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
+    }
+
     return UseProtocolCachePolicy;
 }
 
@@ -2899,8 +2932,7 @@ bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const S
     // FIXME: What about load types other than Standard and Reload?
 
     return (!isFormSubmission || equalLettersIgnoringASCIICase(httpMethod, "get"))
-        && loadType != FrameLoadType::Reload
-        && loadType != FrameLoadType::ReloadFromOrigin
+        && !isReload(loadType)
         && loadType != FrameLoadType::Same
         && !shouldReload(m_frame.document()->url(), url)
         // We don't want to just scroll if a link from within a
@@ -3447,6 +3479,7 @@ void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, FrameLoadType loa
         switch (loadType) {
         case FrameLoadType::Reload:
         case FrameLoadType::ReloadFromOrigin:
+        case FrameLoadType::ReloadExpiredOnly:
             request.setCachePolicy(ReloadIgnoringCacheData);
             break;
         case FrameLoadType::Back:
@@ -3466,7 +3499,7 @@ void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, FrameLoadType loa
         case FrameLoadType::RedirectWithLockedBackForwardList:
             break;
         case FrameLoadType::Same:
-        default:
+        case FrameLoadType::Replace:
             ASSERT_NOT_REACHED();
         }
 
index d1b954a..741b0e0 100644 (file)
@@ -81,6 +81,7 @@ struct FrameLoadRequest;
 struct WindowFeatures;
 
 WEBCORE_EXPORT bool isBackForwardLoadType(FrameLoadType);
+WEBCORE_EXPORT bool isReload(FrameLoadType);
 
 class FrameLoader {
     WTF_MAKE_NONCOPYABLE(FrameLoader);
@@ -119,7 +120,7 @@ public:
     WEBCORE_EXPORT void urlSelected(const URL&, const String& target, Event*, LockHistory, LockBackForwardList, ShouldSendReferrer, ShouldOpenExternalURLsPolicy, std::optional<NewFrameOpenerPolicy> = std::nullopt, const AtomicString& downloadAttribute = nullAtom);
     void submitForm(Ref<FormSubmission>&&);
 
-    WEBCORE_EXPORT void reload(bool endToEndReload = false, bool contentBlockersEnabled = true);
+    WEBCORE_EXPORT void reload(OptionSet<ReloadOption> = { });
     WEBCORE_EXPORT void reloadWithOverrideEncoding(const String& overrideEncoding);
 
     void open(CachedFrameBase&);
index a8b0334..cbd9700 100644 (file)
@@ -28,6 +28,8 @@
 
 #pragma once
 
+#include <wtf/OptionSet.h>
+
 namespace WebCore {
 
 enum FrameState {
@@ -44,6 +46,12 @@ enum PolicyAction {
     PolicyIgnore
 };
 
+enum class ReloadOption {
+    ExpiredOnly = 1 << 0,
+    FromOrigin  = 1 << 1,
+    DisableContentBlockers = 1 << 2,
+};
+
 enum class FrameLoadType {
     Standard,
     Back,
@@ -54,6 +62,7 @@ enum class FrameLoadType {
     RedirectWithLockedBackForwardList, // FIXME: Merge "lockBackForwardList", "lockHistory", "quickRedirect" and "clientRedirect" into a single concept of redirect.
     Replace,
     ReloadFromOrigin,
+    ReloadExpiredOnly
 };
 
 enum class NewFrameOpenerPolicy {
index a1f5a28..743108b 100644 (file)
@@ -229,6 +229,7 @@ void HistoryController::restoreDocumentState()
     switch (m_frame.loader().loadType()) {
     case FrameLoadType::Reload:
     case FrameLoadType::ReloadFromOrigin:
+    case FrameLoadType::ReloadExpiredOnly:
     case FrameLoadType::Same:
     case FrameLoadType::Replace:
         // Not restoring the document state.
index c941a47..75cae60 100644 (file)
@@ -488,6 +488,11 @@ String DiagnosticLoggingKeys::reloadFromOriginKey()
     return ASCIILiteral("reloadFromOrigin");
 }
 
+String DiagnosticLoggingKeys::reloadRevalidatingExpiredKey()
+{
+    return ASCIILiteral("reloadRevalidatingExpired");
+}
+
 String DiagnosticLoggingKeys::sameLoadKey()
 {
     return ASCIILiteral("sameLoad");
index 35dcd8a..648243e 100644 (file)
@@ -123,6 +123,7 @@ public:
     static String redirectKey();
     static String reloadFromOriginKey();
     static String reloadKey();
+    static String reloadRevalidatingExpiredKey();
     static String replaceKey();
     static String resourceLoadedKey();
     static String resourceResponseSourceKey();
index 233bcc4..c8bffef 100644 (file)
@@ -242,9 +242,9 @@ void UserInputBridge::loadRequest(const FrameLoadRequest& request, InputSource)
     m_page.mainFrame().loader().load(request);
 }
 
-void UserInputBridge::reloadFrame(Frame* frame, bool endToEndReload, bool contentBlockersEnabled, InputSource)
+void UserInputBridge::reloadFrame(Frame* frame, OptionSet<ReloadOption> options, InputSource)
 {
-    frame->loader().reload(endToEndReload, contentBlockersEnabled);
+    frame->loader().reload(options);
 }
 
 void UserInputBridge::stopLoadingFrame(Frame* frame, InputSource)
index 9746211..407e68d 100644 (file)
@@ -27,6 +27,7 @@
 
 #pragma once
 
+#include "FrameLoaderTypes.h"
 #include "ScrollTypes.h"
 #include <wtf/Noncopyable.h>
 
@@ -88,7 +89,7 @@ public:
 
     // Navigation APIs.
     WEBCORE_EXPORT void loadRequest(const FrameLoadRequest&, InputSource source = InputSource::User);
-    WEBCORE_EXPORT void reloadFrame(Frame*, bool endToEndReload, bool contentBlockersEnabled, InputSource = InputSource::User);
+    WEBCORE_EXPORT void reloadFrame(Frame*, OptionSet<ReloadOption>, InputSource = InputSource::User);
     WEBCORE_EXPORT void stopLoadingFrame(Frame*, InputSource source = InputSource::User);
     WEBCORE_EXPORT bool tryClosePage(InputSource source = InputSource::User);
 
index 126dfc4..08da8c6 100644 (file)
@@ -2838,7 +2838,16 @@ void Internals::setUsesMockScrollAnimator(bool enabled)
 
 void Internals::forceReload(bool endToEnd)
 {
-    frame()->loader().reload(endToEnd);
+    OptionSet<ReloadOption> reloadOptions;
+    if (endToEnd)
+        reloadOptions |= ReloadOption::FromOrigin;
+
+    frame()->loader().reload(reloadOptions);
+}
+
+void Internals::reloadExpiredOnly()
+{
+    frame()->loader().reload(ReloadOption::ExpiredOnly);
 }
 
 void Internals::enableAutoSizeMode(bool enabled, int minimumWidth, int minimumHeight, int maximumWidth, int maximumHeight)
index 68545a4..52c4d59 100644 (file)
@@ -388,6 +388,7 @@ public:
     String toolTipFromElement(Element&) const;
 
     void forceReload(bool endToEnd);
+    void reloadExpiredOnly();
 
     void enableAutoSizeMode(bool enabled, int minimumWidth, int minimumHeight, int maximumWidth, int maximumHeight);
 
index 5dc1b35..a65c384 100644 (file)
@@ -392,6 +392,7 @@ enum EventThrottlingBehavior {
     void setUsesMockScrollAnimator(boolean enabled);
 
     void forceReload(boolean endToEnd);
+    void reloadExpiredOnly();
 
     void enableAutoSizeMode(boolean enabled, long minimumWidth, long minimumHeight, long maximumWidth, long maximumHeight);
 
index 0d4f2c1..5988ed1 100644 (file)
@@ -1,3 +1,15 @@
+2017-03-17  Antti Koivisto  <antti@apple.com>
+
+        Add a reload policy where only expired subresources are revalidated
+        https://bugs.webkit.org/show_bug.cgi?id=169756
+
+        Reviewed by Andreas Kling.
+
+        * WebView/WebFrame.mm:
+        (toWebFrameLoadType):
+        (-[WebFrame reload]):
+        (-[WebFrame reloadFromOrigin]):
+
 2017-03-17  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [WK1] Support animated transitions when performing a data interaction operation
index fdd241a..b2c27b5 100644 (file)
@@ -1059,6 +1059,9 @@ static WebFrameLoadType toWebFrameLoadType(FrameLoadType frameLoadType)
         return WebFrameLoadTypeReplace;
     case FrameLoadType::ReloadFromOrigin:
         return WebFrameLoadTypeReloadFromOrigin;
+    case FrameLoadType::ReloadExpiredOnly:
+        ASSERT_NOT_REACHED();
+        return WebFrameLoadTypeReload;
     }
 }
 
@@ -2539,12 +2542,12 @@ static NSURL *createUniqueWebDataURL()
 
 - (void)reload
 {
-    _private->coreFrame->loader().reload(false);
+    _private->coreFrame->loader().reload({ });
 }
 
 - (void)reloadFromOrigin
 {
-    _private->coreFrame->loader().reload(true);
+    _private->coreFrame->loader().reload(WebCore::ReloadOption::FromOrigin);
 }
 
 - (WebFrame *)findFrameNamed:(NSString *)name
index 29ff243..bf2a0eb 100644 (file)
@@ -306,7 +306,7 @@ HRESULT WebFrame::reloadFromOrigin()
     if (!coreFrame)
         return E_UNEXPECTED;
 
-    coreFrame->loader().reload(true);
+    coreFrame->loader().reload(WebCore::ReloadOption::FromOrigin);
     return S_OK;
 }
 
index 91e6a26..003c6d6 100644 (file)
@@ -1,3 +1,38 @@
+2017-03-17  Antti Koivisto  <antti@apple.com>
+
+        Add a reload policy where only expired subresources are revalidated
+        https://bugs.webkit.org/show_bug.cgi?id=169756
+
+        Reviewed by Andreas Kling.
+
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageReload):
+        (WKPageReloadWithoutContentBlockers):
+        (WKPageReloadFromOrigin):
+        (WKPageReloadExpiredOnly):
+        * UIProcess/API/C/WKPage.h:
+        * UIProcess/API/Cocoa/WKBrowsingContextController.mm:
+        (-[WKBrowsingContextController reload]):
+        (-[WKBrowsingContextController reloadFromOrigin]):
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView reload]):
+        (-[WKWebView reloadFromOrigin]):
+        (-[WKWebView _reloadWithoutContentBlockers]):
+        (-[WKWebView _reloadExpiredOnly]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/Automation/WebAutomationSession.cpp:
+        (WebKit::WebAutomationSession::reloadBrowsingContext):
+        * UIProcess/WebFrameProxy.cpp:
+        (WebKit::WebFrameProxy::didHandleContentFilterUnblockNavigation):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::reload):
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::reload):
+        (WebKit::shouldReuseCommittedSandboxExtension):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2017-03-16  Alex Christensen  <achristensen@webkit.org>
 
         Use completion handlers instead of return values for sending websocket data
index 053be18..f9620b2 100644 (file)
@@ -242,23 +242,22 @@ void WKPageStopLoading(WKPageRef pageRef)
 
 void WKPageReload(WKPageRef pageRef)
 {
-    const bool reloadFromOrigin = false;
-    const bool contentBlockersEnabled = true;
-    toImpl(pageRef)->reload(reloadFromOrigin, contentBlockersEnabled);
+    toImpl(pageRef)->reload({ });
 }
 
 void WKPageReloadWithoutContentBlockers(WKPageRef pageRef)
 {
-    const bool reloadFromOrigin = false;
-    const bool contentBlockersEnabled = false;
-    toImpl(pageRef)->reload(reloadFromOrigin, contentBlockersEnabled);
+    toImpl(pageRef)->reload(WebCore::ReloadOption::DisableContentBlockers);
 }
 
 void WKPageReloadFromOrigin(WKPageRef pageRef)
 {
-    const bool reloadFromOrigin = true;
-    const bool contentBlockersEnabled = true;
-    toImpl(pageRef)->reload(reloadFromOrigin, contentBlockersEnabled);
+    toImpl(pageRef)->reload(WebCore::ReloadOption::FromOrigin);
+}
+
+void WKPageReloadExpiredOnly(WKPageRef pageRef)
+{
+    toImpl(pageRef)->reload(WebCore::ReloadOption::ExpiredOnly);
 }
 
 bool WKPageTryClose(WKPageRef pageRef)
index 6d53120..a2607c0 100644 (file)
@@ -84,6 +84,7 @@ WK_EXPORT void WKPageStopLoading(WKPageRef page);
 WK_EXPORT void WKPageReload(WKPageRef page);
 WK_EXPORT void WKPageReloadWithoutContentBlockers(WKPageRef page);
 WK_EXPORT void WKPageReloadFromOrigin(WKPageRef page);
+WK_EXPORT void WKPageReloadExpiredOnly(WKPageRef page);
 
 WK_EXPORT bool WKPageTryClose(WKPageRef page);
 WK_EXPORT void WKPageClose(WKPageRef page);
index 061eb4b..2aee0c9 100644 (file)
@@ -187,16 +187,12 @@ static HashMap<WebPageProxy*, WKBrowsingContextController *>& browsingContextCon
 
 - (void)reload
 {
-    const bool reloadFromOrigin = false;
-    const bool contentBlockersEnabled = true;
-    _page->reload(reloadFromOrigin, contentBlockersEnabled);
+    _page->reload({ });
 }
 
 - (void)reloadFromOrigin
 {
-    const bool reloadFromOrigin = true;
-    const bool contentBlockersEnabled = true;
-    _page->reload(reloadFromOrigin, contentBlockersEnabled);
+    _page->reload(WebCore::ReloadOption::FromOrigin);
 }
 
 - (NSString *)applicationNameForUserAgent
index d5d3f90..9073fc7 100644 (file)
@@ -844,9 +844,7 @@ static uint32_t convertSystemLayoutDirection(NSUserInterfaceLayoutDirection dire
 
 - (WKNavigation *)reload
 {
-    const bool reloadFromOrigin = false;
-    const bool contentBlockersEnabled = true;
-    auto navigation = _page->reload(reloadFromOrigin, contentBlockersEnabled);
+    auto navigation = _page->reload({ });
     if (!navigation)
         return nil;
 
@@ -855,9 +853,7 @@ static uint32_t convertSystemLayoutDirection(NSUserInterfaceLayoutDirection dire
 
 - (WKNavigation *)reloadFromOrigin
 {
-    const bool reloadFromOrigin = true;
-    const bool contentBlockersEnabled = true;
-    auto navigation = _page->reload(reloadFromOrigin, contentBlockersEnabled);
+    auto navigation = _page->reload(WebCore::ReloadOption::FromOrigin);
     if (!navigation)
         return nil;
 
@@ -3692,9 +3688,16 @@ WEBCORE_COMMAND(yankAndSelect)
 
 - (WKNavigation *)_reloadWithoutContentBlockers
 {
-    const bool reloadFromOrigin = false;
-    const bool contentBlockersEnabled = false;
-    auto navigation = _page->reload(reloadFromOrigin, contentBlockersEnabled);
+    auto navigation = _page->reload(WebCore::ReloadOption::DisableContentBlockers);
+    if (!navigation)
+        return nil;
+    
+    return [wrapper(*navigation.leakRef()) autorelease];
+}
+
+- (WKNavigation *)_reloadExpiredOnly
+{
+    auto navigation = _page->reload(WebCore::ReloadOption::ExpiredOnly);
     if (!navigation)
         return nil;
     
index 68731f4..bae13a7 100644 (file)
@@ -228,6 +228,7 @@ typedef NS_ENUM(NSInteger, _WKImmediateActionType) {
 #endif
 
 - (WKNavigation *)_reloadWithoutContentBlockers WK_API_AVAILABLE(macosx(10.12), ios(10.0));
+- (WKNavigation *)_reloadExpiredOnly WK_API_AVAILABLE(macosx(10.13), ios(11.0));
 
 - (void)_killWebContentProcessAndResetState;
 
index 5b02639..c3205ee 100644 (file)
@@ -2539,9 +2539,7 @@ void webkit_web_view_reload(WebKitWebView* webView)
 {
     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
 
-    const bool reloadFromOrigin = false;
-    const bool contentBlockersEnabled = true;
-    getPage(webView)->reload(reloadFromOrigin, contentBlockersEnabled);
+    getPage(webView)->reload({ });
 }
 
 /**
@@ -2555,9 +2553,7 @@ void webkit_web_view_reload_bypass_cache(WebKitWebView* webView)
 {
     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
 
-    const bool reloadFromOrigin = true;
-    const bool contentBlockersEnabled = true;
-    getPage(webView)->reload(reloadFromOrigin, contentBlockersEnabled);
+    getPage(webView)->reload(WebCore::ReloadOption::FromOrigin);
 }
 
 /**
index b0b7ccc..57d385d 100644 (file)
@@ -341,8 +341,7 @@ void WebAutomationSession::reloadBrowsingContext(Inspector::ErrorString& errorSt
         callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
     m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page->pageID(), WTFMove(callback));
 
-    const bool reloadFromOrigin = false;
-    page->reload(reloadFromOrigin, { });
+    page->reload({ });
 }
 
 void WebAutomationSession::navigationOccurredForPage(const WebPageProxy& page)
index e424adf..6bcc478 100644 (file)
@@ -248,11 +248,8 @@ bool WebFrameProxy::didHandleContentFilterUnblockNavigation(const WebCore::Resou
     RefPtr<WebPageProxy> page { m_page };
     ASSERT(page);
     m_contentFilterUnblockHandler.requestUnblockAsync([page](bool unblocked) {
-        if (unblocked) {
-            const bool reloadFromOrigin = false;
-            const bool contentBlockersEnabled = true;
-            page->reload(reloadFromOrigin, contentBlockersEnabled);
-        }
+        if (unblocked)
+            page->reload({ });
     });
     return true;
 }
index 61d7cef..9570ff3 100644 (file)
@@ -1164,7 +1164,7 @@ void WebPageProxy::stopLoading()
     m_process->responsivenessTimer().start();
 }
 
-RefPtr<API::Navigation> WebPageProxy::reload(bool reloadFromOrigin, bool contentBlockersEnabled)
+RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
 {
     SandboxExtension::Handle sandboxExtensionHandle;
 
@@ -1187,7 +1187,7 @@ RefPtr<API::Navigation> WebPageProxy::reload(bool reloadFromOrigin, bool content
     
     auto navigation = m_navigationState->createReloadNavigation();
 
-    m_process->send(Messages::WebPage::Reload(navigation->navigationID(), reloadFromOrigin, contentBlockersEnabled, sandboxExtensionHandle), m_pageID);
+    m_process->send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle), m_pageID);
     m_process->responsivenessTimer().start();
 
     return WTFMove(navigation);
index 74230df..e32fd89 100644 (file)
@@ -404,7 +404,7 @@ public:
     void navigateToPDFLinkWithSimulatedClick(const String& url, WebCore::IntPoint documentPoint, WebCore::IntPoint screenPoint);
 
     void stopLoading();
-    RefPtr<API::Navigation> reload(bool reloadFromOrigin, bool contentBlockersEnabled);
+    RefPtr<API::Navigation> reload(OptionSet<WebCore::ReloadOption>);
 
     RefPtr<API::Navigation> goForward();
     RefPtr<API::Navigation> goBack();
index dd6afe1..0b538aa 100644 (file)
@@ -1315,7 +1315,7 @@ void WebPage::setDefersLoading(bool defersLoading)
     m_page->setDefersLoading(defersLoading);
 }
 
-void WebPage::reload(uint64_t navigationID, bool reloadFromOrigin, bool contentBlockersEnabled, const SandboxExtension::Handle& sandboxExtensionHandle)
+void WebPage::reload(uint64_t navigationID, uint32_t reloadOptions, const SandboxExtension::Handle& sandboxExtensionHandle)
 {
     SendStopResponsivenessTimer stopper(this);
 
@@ -1323,7 +1323,7 @@ void WebPage::reload(uint64_t navigationID, bool reloadFromOrigin, bool contentB
     m_pendingNavigationID = navigationID;
 
     m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), sandboxExtensionHandle);
-    corePage()->userInputBridge().reloadFrame(m_mainFrame->coreFrame(), reloadFromOrigin, contentBlockersEnabled);
+    corePage()->userInputBridge().reloadFrame(m_mainFrame->coreFrame(), OptionSet<ReloadOption>::fromRaw(reloadOptions));
 }
 
 void WebPage::goForward(uint64_t navigationID, uint64_t backForwardItemID)
@@ -4140,7 +4140,7 @@ static bool shouldReuseCommittedSandboxExtension(WebFrame* frame)
     FrameLoadType frameLoadType = frameLoader.loadType();
 
     // If the page is being reloaded, it should reuse whatever extension is committed.
-    if (frameLoadType == FrameLoadType::Reload || frameLoadType == FrameLoadType::ReloadFromOrigin)
+    if (isReload(frameLoadType))
         return true;
 
     DocumentLoader* documentLoader = frameLoader.documentLoader();
index ce5d368..2102296 100644 (file)
@@ -1047,7 +1047,7 @@ private:
     void loadString(const LoadParameters&);
     void loadAlternateHTMLString(const LoadParameters&);
     void navigateToPDFLinkWithSimulatedClick(const String& url, WebCore::IntPoint documentPoint, WebCore::IntPoint screenPoint);
-    void reload(uint64_t navigationID, bool reloadFromOrigin, bool contentBlockersEnabled, const SandboxExtension::Handle&);
+    void reload(uint64_t navigationID, uint32_t reloadOptions, const SandboxExtension::Handle&);
     void goForward(uint64_t navigationID, uint64_t);
     void goBack(uint64_t navigationID, uint64_t);
     void goToBackForwardItem(uint64_t navigationID, uint64_t);
index cf4f465..c701ae9 100644 (file)
@@ -140,7 +140,7 @@ messages -> WebPage LegacyReceiver {
 
     NavigateToPDFLinkWithSimulatedClick(String url, WebCore::IntPoint documentPoint, WebCore::IntPoint screenPoint)
 
-    Reload(uint64_t navigationID, bool reloadFromOrigin, bool contentBlockersEnabled, WebKit::SandboxExtension::Handle sandboxExtensionHandle)
+    Reload(uint64_t navigationID, uint32_t reloadOptions, WebKit::SandboxExtension::Handle sandboxExtensionHandle)
     StopLoading()
 
     StopLoadingFrame(uint64_t frameID)