[Content Filtering] Load blocked pages more like other error pages are loaded
https://bugs.webkit.org/show_bug.cgi?id=159485
<rdar://problem/26014076>

Reviewed by Brady Eidson.

Source/WebCore:

Content filter blocked pages were being loaded by cancelling the provisional load of the
page that was blocked and then scheduling a navigation to the content filter error page.
Some clients would not expect a new, Web process-initiated provisional navigation to start
after a cancellation, though, and this would put them in a bad state.

This patch changes blocked page loading to behave more like loading other error pages.
Specifically:
1. didFailProvisionalLoad is dispatched with a new, non-cancellation error code.
2. The blocked page is loaded immediately after dispatching didFailProvisionalLoad, which
   prevents FrameLoader from creating a new back-forward list item for the substitute data load.
3. A substitute data load initiated by the client for the blocked URL is ignored if
   ContentFilter will display its own error page.
4. A file: URL is used instead of a custom scheme for the base URL of the blocked page,
   since some clients expect this.

Updated existing tests to capture frame load delegate callbacks and the back forward list.
Added new API tests: ContentFiltering.LoadAlternate*.

* English.lproj/Localizable.strings: Added a WebKitErrorFrameLoadBlockedByContentFilter description.
* Resources/ContentFilterBlockedPage.html: Added.
* WebCore.xcodeproj/project.pbxproj: Added ContentFilterBlockedPage.html as a frameowrk resource.
* loader/ContentFilter.cpp:
(WebCore::ContentFilter::continueAfterWillSendRequest): Protected m_documentLoader,
since it might otherwise be deallocated inside ContentFilter::didDecide() if the load is blocked.
(WebCore::ContentFilter::stopFilteringMainResource): Only set m_state to Stopped if not
already Blocked, so that we don't forget this ContentFilter was blocked when calling
cancelMailResourceLoad() in didDecide().
(WebCore::ContentFilter::continueAfterResponseReceived): Protected m_documentLoader,
since it might otherwise be deallocated inside ContentFilter::didDecide() if the load is blocked.
(WebCore::ContentFilter::continueAfterDataReceived): Ditto.
(WebCore::ContentFilter::continueAfterNotifyFinished): Ditto.
(WebCore::ContentFilter::didDecide): Moved code from DocumentLoader::contentFilterDidBlock() to here.
Created a blockedByContentFilterError() and called cancelMainResourceLoad().
(WebCore::blockedPageURL): Returned a file: URL to ContentFilterBlockedPage.html in WebCore.framework.
(WebCore::ContentFilter::continueAfterSubstituteDataRequest): If the substitute data load
is for the same failingURL as the currently-displayed blocked page, ignore it.
(WebCore::ContentFilter::handleProvisionalLoadFailure): Load the blocked page if m_state is Blocked
and the ResourceError matches the error we used when previously calling cancelMainResourceLoad().
(WebCore::ContentFilter::unblockHandler): Deleted.
(WebCore::ContentFilter::replacementData): Deleted.
(WebCore::ContentFilter::unblockRequestDeniedScript): Deleted.
* loader/ContentFilter.h:
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::contentFilter): Returned m_contentFilter.
(WebCore::DocumentLoader::installContentFilterUnblockHandler): Deleted.
(WebCore::DocumentLoader::contentFilterDidBlock): Deleted.
* loader/DocumentLoader.h:
* loader/EmptyClients.h: Added a default implementation of blockedByContentFilterError().
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::load): If m_loadType was already RedirectWithLockedBackForwardList
and we are loading subsitute data for a failing URL, continue to use RedirectWithLockedBackForwardList.
This prevents a new back-forward list item from being created when loading a blocked page in a subframe.
(WebCore::FrameLoader::checkLoadCompleteForThisFrame):
Called ContentFilter::handleProvisionalLoadFailure() after dispatchDidFailProvisionalLoad().
(WebCore::FrameLoader::blockedByContentFilterError): Called FrameLoaderClient::blockedByContentFilterError().
* loader/FrameLoader.h:
* loader/FrameLoaderClient.h:
* loader/NavigationScheduler.cpp:
(WebCore::ScheduledSubstituteDataLoad::ScheduledSubstituteDataLoad): Deleted.
(WebCore::NavigationScheduler::scheduleSubstituteDataLoad): Deleted.
* loader/NavigationScheduler.h:
* loader/PolicyChecker.cpp:
(WebCore::PolicyChecker::checkNavigationPolicy): Ignored a substitute data load for a
failing URL if ContentFilter::continueAfterSubstituteDataRequest() returns false.

Source/WebKit/mac:

* Misc/WebKitErrors.h: Defined WebKitErrorFrameLoadBlockedByContentFilter.
* Misc/WebKitErrors.m:
(registerErrors): Registered WebKitErrorDescriptionFrameLoadBlockedByContentFilter.
* WebCoreSupport/WebFrameLoaderClient.h:
* WebCoreSupport/WebFrameLoaderClient.mm:
(WebFrameLoaderClient::blockedByContentFilterError): Returned a ResourceError for WebKitErrorFrameLoadBlockedByContentFilter.

Source/WebKit2:

* Shared/API/c/WKErrorRef.h: Defined kWKErrorCodeFrameLoadBlockedByContentFilter.
* UIProcess/Cocoa/WebProcessProxyCocoa.mm:
(WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): Added the resource directories
of WebCore.framework and WebKit.framework as paths with assumed read access.
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::hasAssumedReadAccessToURL): Checked platformPathsWithAssumedReadAccess()
as well as m_localPathsWithAssumedReadAccess.
(WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): Added a non-Cocoa implementation.
* UIProcess/WebProcessProxy.h:
* WebProcess/WebCoreSupport/WebErrors.h:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::blockedByContentFilterError): Called WebKit::blockedByContentFilterError().
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
* WebProcess/WebCoreSupport/mac/WebErrorsMac.mm:
(WebKit::blockedByContentFilterError): Returned a ResourceError for kWKErrorCodeFrameLoadBlockedByContentFilter.

Tools:

Added API tests for WebView and WKWebView to verify that alternate HTML loaded in response
to a content filtering provisional navigation failure is ignored in preference of
ContentFilter's own error page.

* TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm:
(-[LoadAlternateNavigationDelegate webView:didFailProvisionalNavigation:withError:]):
(-[LoadAlternateNavigationDelegate webView:didFinishNavigation:]):
(loadAlternateTest):
(TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm:
(-[MockContentFilterEnabler initWithCoder:]):
* TestWebKitAPI/Tests/mac/ContentFiltering.mm: Added.
(-[LoadAlternateFrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
(-[LoadAlternateFrameLoadDelegate webView:didFinishLoadForFrame:]):
(TestWebKitAPI::loadAlternateTest):
(TestWebKitAPI::TEST):

LayoutTests:

Changed allow-* and block-* tests from ref tests to text tests so that they can capture
frame load delegate callbacks and the back forward list.

* contentfiltering/allow-after-add-data-expected.html: Removed.
* contentfiltering/allow-after-add-data-expected.txt: Added.
* contentfiltering/allow-after-finished-adding-data-expected.html: Removed.
* contentfiltering/allow-after-finished-adding-data-expected.txt: Added.
* contentfiltering/allow-after-response-expected.html: Removed.
* contentfiltering/allow-after-response-expected.txt: Added.
* contentfiltering/allow-after-will-send-request-expected.html: Removed.
* contentfiltering/allow-after-will-send-request-expected.txt: Added.
* contentfiltering/allow-never-expected.html: Removed.
* contentfiltering/allow-never-expected.txt: Added.
* contentfiltering/block-after-add-data-expected.html: Removed.
* contentfiltering/block-after-add-data-expected.txt: Added.
* contentfiltering/block-after-add-data-then-allow-unblock-expected.html: Removed.
* contentfiltering/block-after-add-data-then-allow-unblock-expected.txt: Added.
* contentfiltering/block-after-add-data-then-deny-unblock-expected.html: Removed.
* contentfiltering/block-after-add-data-then-deny-unblock-expected.txt: Added.
* contentfiltering/block-after-finished-adding-data-expected.html: Removed.
* contentfiltering/block-after-finished-adding-data-expected.txt: Added.
* contentfiltering/block-after-finished-adding-data-then-allow-unblock-expected.html: Removed.
* contentfiltering/block-after-finished-adding-data-then-allow-unblock-expected.txt: Added.
* contentfiltering/block-after-finished-adding-data-then-deny-unblock-expected.html: Removed.
* contentfiltering/block-after-finished-adding-data-then-deny-unblock-expected.txt: Added.
* contentfiltering/block-after-response-expected.html: Removed.
* contentfiltering/block-after-response-expected.txt: Added.
* contentfiltering/block-after-response-then-allow-unblock-expected.html: Removed.
* contentfiltering/block-after-response-then-allow-unblock-expected.txt: Added.
* contentfiltering/block-after-response-then-deny-unblock-expected.html: Removed.
* contentfiltering/block-after-response-then-deny-unblock-expected.txt: Added.
* contentfiltering/block-after-will-send-request-expected.html: Removed.
* contentfiltering/block-after-will-send-request-expected.txt: Added.
* contentfiltering/block-after-will-send-request-then-allow-unblock-expected.html: Removed.
* contentfiltering/block-after-will-send-request-then-allow-unblock-expected.txt: Added.
* contentfiltering/block-after-will-send-request-then-deny-unblock-expected.html: Removed.
* contentfiltering/block-after-will-send-request-then-deny-unblock-expected.txt: Added.
* contentfiltering/block-never-expected.html: Removed.
* contentfiltering/block-never-expected.txt: Added.
* contentfiltering/resources/contentfiltering.js: Added testRunner calls to dump as text,
dump frame load callbacks, and dump the back forward list. Changed from loading data: URLs
to file: URLs in the test iframe.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@203003 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/loader/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp
index 4f8d0cf..0441831 100644
--- a/Source/WebCore/loader/NavigationScheduler.cpp
+++ b/Source/WebCore/loader/NavigationScheduler.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2010, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
  * Copyright (C) 2009 Adam Barth. All rights reserved.
@@ -323,26 +323,6 @@
     Document& m_originDocument;
 };
 
-class ScheduledSubstituteDataLoad : public ScheduledNavigation {
-public:
-    ScheduledSubstituteDataLoad(const URL& baseURL, const SubstituteData& substituteData)
-        : ScheduledNavigation { 0, LockHistory::No, LockBackForwardList::No, false, false }
-        , m_baseURL { baseURL }
-        , m_substituteData { substituteData }
-    {
-    }
-
-    void fire(Frame& frame) override
-    {
-        UserGestureIndicator gestureIndicator { wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture };
-        frame.loader().load(FrameLoadRequest { &frame, m_baseURL, m_shouldOpenExternalURLsPolicy, m_substituteData });
-    }
-
-private:
-    URL m_baseURL;
-    SubstituteData m_substituteData;
-};
-
 NavigationScheduler::NavigationScheduler(Frame& frame)
     : m_frame(frame)
     , m_timer(*this, &NavigationScheduler::timerFired)
@@ -499,12 +479,6 @@
     schedule(std::make_unique<ScheduledHistoryNavigation>(steps));
 }
 
-void NavigationScheduler::scheduleSubstituteDataLoad(const URL& baseURL, const SubstituteData& substituteData)
-{
-    if (shouldScheduleNavigation())
-        schedule(std::make_unique<ScheduledSubstituteDataLoad>(baseURL, substituteData));
-}
-
 void NavigationScheduler::schedulePageBlock(Document& originDocument)
 {
     if (shouldScheduleNavigation())