[Content Filtering] Add tests for unblock requests
authoraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Mar 2015 08:42:59 +0000 (08:42 +0000)
committeraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Mar 2015 08:42:59 +0000 (08:42 +0000)
commitbe323ef921cef9bedbfa3adea1ac1de66d26acfc
tree72969a15f9d3afb5e416b48fea73850c83c7f523
parent4b15820901a56ec300ffa1740a3e6737b38778d8
[Content Filtering] Add tests for unblock requests
https://bugs.webkit.org/show_bug.cgi?id=142900

Reviewed by Andreas Kling.

Source/WebCore:

Currently the iOS Parental Controls content filter has a mechanism for requesting that a page be unblocked.
WebKit implements this by listening for navigations originating from the filter's error page to a special URL,
and requesting the page be unblocked via platform API, which might cause UI to be displayed. If the unblock is
successful then we schedule a reload of the frame in order to display the unblocked document.

NetworkExtension also supports unblock requests, so in preparation for adopting its API, this patch allows
content filters to specify their own unblock request method, teaches MockContentFilter to provide such a method,
and writes tests to cover both allowed and denied unblock requests.

The content filter that blocks a load creates a ContentFilterUnblockHandler, passing it a lambda that is executed
when a navigation matches the filter's special unblock URL. Filters can also specify that a script be executed in
the context of its error page if the unblock is denied.

All platform content filters can handle unblock requests like this with the exception of iOS Parental Controls in WebKit2.
Since UI can be displayed by the system in this case, the request must be made from within the UI process. Therefore the
existing method is retained of serializing a WebFilterEvaluator and intercepting navigation policy calls in the UI process.

Tests: contentfiltering/allow-after-unblock-request.html
       contentfiltering/block-after-unblock-request.html

* bindings/js/JSMockContentFilterSettingsCustom.cpp:
(WebCore::JSMockContentFilterSettings::decisionPoint): Added some using statements for clarity.
(WebCore::JSMockContentFilterSettings::setDecisionPoint): Ditto.
(WebCore::toJSValue): Returns a JSValue from a Decision.
(WebCore::toDecision): Returns a Decision from a JSValue.
(WebCore::JSMockContentFilterSettings::decision): Used toJSValue.
(WebCore::JSMockContentFilterSettings::setDecision): Used toDecision.
(WebCore::JSMockContentFilterSettings::unblockRequestDecision): Used toJSValue.
(WebCore::JSMockContentFilterSettings::setUnblockRequestDecision): Used toDecision.
* loader/ContentFilter.cpp:
(WebCore::ContentFilter::createIfNeeded): Passed a reference to the owning DocumentLoader.
(WebCore::ContentFilter::ContentFilter): Ditto.
(WebCore::ContentFilter::unblockHandler): If the unblockHandler requests that a script be executed when an
unblock request is denied, create a wrapper unblockHandler that executes that script in m_documentLoader's frame.
* loader/ContentFilter.h:
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::responseReceived): Passed this to ContentFilter::createIfNeeded.
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::prepareForLoadStart): Called PolicyChecker::prepareForLoadStart.
* loader/PolicyChecker.cpp:
(WebCore::PolicyChecker::prepareForLoadStart): Reset m_contentFilterUnblockHandler.
(WebCore::PolicyChecker::checkNavigationPolicy): Moved logic to here from WebKit1's WebFrameLoaderClient.
Placing it here allows it to be shared between WebKit1 and WebKit2 (when the unblock handler does not need to
be called in the UI process).
* loader/PolicyChecker.h:
(WebCore::PolicyChecker::setContentFilterUnblockHandler): Added.
* page/Frame.h: Made Frame ThreadSafeRefCounted, since RefPtr<Frames> are captured in lambdas that can be
copied by background threads managed by the underlying platform.
* platform/ContentFilterUnblockHandler.h:
(WebCore::ContentFilterUnblockHandler::unblockURLScheme): Returned the Apple content filter scheme.
(WebCore::ContentFilterUnblockHandler::unblockURLHost): Returned the unblock URL host.
(WebCore::ContentFilterUnblockHandler::clear): Deleted.
* platform/PlatformContentFilter.h:
(WebCore::PlatformContentFilter::unblockRequestDeniedScript): Returned the unblock request denied script.
* platform/cocoa/ContentFilterUnblockHandlerCocoa.mm:
(WebCore::ContentFilterUnblockHandler::ContentFilterUnblockHandler): Added a constructor that takes an
unblockURLHost and a UnblockRequesterFunction. Added an alternate constructor for iOS Parental Controls on
WebKit2 that takes an unblockURLHost and a WebFilterEvaluator.
(WebCore::ContentFilterUnblockHandler::needsUIProcess): Returned true if m_webFilterEvaluator is non-null.
(WebCore::ContentFilterUnblockHandler::encode): Encoded m_unblockURLHost in addition to m_webFilterEvaluator.
(WebCore::ContentFilterUnblockHandler::decode): Decoded m_unblockURLHost in addition to m_webFilterEvaluator.
(WebCore::ContentFilterUnblockHandler::canHandleRequest): Returned true if there is a either a m_unblockRequester
or a m_webFilterEvaluator and the request's host and scheme match those of the unblock request URL.
(WebCore::dispatchToMainThread): Added a helper to dispatch a block to the main thread. Then if the web thread
is enabled on iOS, dispatch it there.
(WebCore::ContentFilterUnblockHandler::requestUnblockAsync): Renamed from handleUnblockRequestAndDispatchIfSuccessful.
Requested an unblock using either m_unblockRequester or m_webFilterEvaluator, then called decisionHandler with the response.
(WebCore::scheme): Moved to ContentFilterUnblockHandler::unblockURLScheme.
(WebCore::ContentFilterUnblockHandler::handleUnblockRequestAndDispatchIfSuccessful): Renamed to requestUnblockAsync.
* platform/cocoa/ParentalControlsContentFilter.mm:
(WebCore::ParentalControlsContentFilter::unblockHandler): Returned an unblock handler using the WebFilterEvaluator constructor.
* testing/MockContentFilter.cpp: Added using statments for clarity.
(WebCore::settings): Added a helper to get MockContentFilterSettings::singleton().
(WebCore::MockContentFilter::canHandleResponse): Used the helper.
(WebCore::MockContentFilter::MockContentFilter): Took advantage of the using statements.
(WebCore::MockContentFilter::addData): Ditto.
(WebCore::MockContentFilter::finishedAddingData): Ditto.
(WebCore::MockContentFilter::unblockHandler): Returned a ContentFilterUnblockHandler that checks settings() for its decision.
(WebCore::MockContentFilter::unblockRequestDeniedScript): Returned the script to execute in MockContentFilter's
error page when an unblock request is denied.
(WebCore::MockContentFilter::maybeDetermineStatus): Took advantage of settings() and using statements.
* testing/MockContentFilterSettings.cpp:
(WebCore::MockContentFilterSettings::unblockRequestURL): Constructed a static unblock URL and returned it.
* testing/MockContentFilterSettings.h:
(WebCore::MockContentFilterSettings::unblockURLHost): Returned the filter's unblock URL host.
(WebCore::MockContentFilterSettings::unblockRequestDecision): Returns the decision to make for an unblock request.
(WebCore::MockContentFilterSettings::setUnblockRequestDecision): Sets the decision to make for an unblock request.
* testing/MockContentFilterSettings.idl: Added the unblockRequestDecision and unblockRequestURL attributes.

Source/WebKit/mac:

* WebCoreSupport/WebFrameLoaderClient.mm:
(WebFrameLoaderClient::dispatchDidStartProvisionalLoad): This now happens in PolicyChecker.
(WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction): Ditto.
* WebView/WebFrame.mm:
(-[WebFrame _contentFilterDidHandleNavigationAction:]): Deleted.
* WebView/WebFrameInternal.h: Removed contentFilterUnblockHandler from WebFramePrivate.

Source/WebKit2:

* UIProcess/Cocoa/WebPageProxyCocoa.mm:
(WebKit::WebPageProxy::contentFilterDidBlockLoadForFrame): Called WebFrameProxy::contentFilterDidBlockLoad.
* UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::didStartProvisionalLoad): Assigned a default-constructed ContentFilterUnblockHandler instead of calling clear().
(WebKit::WebFrameProxy::didHandleContentFilterUnblockNavigation): Renamed from contentFilterDidHandleNavigationAction.
Updated to use ContentFilterUnblockHandler's new API.
(WebKit::WebFrameProxy::contentFilterDidHandleNavigationAction): Deleted.
* UIProcess/WebFrameProxy.h:
(WebKit::WebFrameProxy::contentFilterDidBlockLoad): Renamed from setContentFilterUnblockHandler.
(WebKit::WebFrameProxy::setContentFilterUnblockHandler): Deleted.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::decidePolicyForNavigationAction): Called WebFrameProxy::didHandleContentFilterUnblockNavigation.
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::contentFilterDidBlockLoad): If the unblock handler needs the UI process,
send WebPageProxy::ContentFilterDidBlockLoadForFrame. Oterwise, call PolicyChecker::setContentFilterUnblockHandler.

LayoutTests:

Taught contentfiltering.js how to perform an unblock request test, and added tests for both allowed and blocked requests.

* contentfiltering/allow-after-unblock-request-expected.html: Added.
* contentfiltering/allow-after-unblock-request.html: Added.
* contentfiltering/block-after-unblock-request-expected.html: Added.
* contentfiltering/block-after-unblock-request.html: Added.
* contentfiltering/resources/contentfiltering.js:
(testContentFiltering): Added an argument specifying if the decision applies to the initial load or the unblock request.
(_doTest): When testing unblock handling, navigate the test iframe to settings.unblockRequestURL when the error page is displayed.
If the unblock is denied, the test harness will call window.unblockRequestDenied(). If the unblock is successful,
the iframe will reload, which we detect by listening for its load event.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181791 268f45cc-cd09-0410-ab3c-d52691b4dbfc
34 files changed:
LayoutTests/ChangeLog
LayoutTests/contentfiltering/allow-after-unblock-request-expected.html [new file with mode: 0644]
LayoutTests/contentfiltering/allow-after-unblock-request.html [new file with mode: 0644]
LayoutTests/contentfiltering/block-after-unblock-request-expected.html [new file with mode: 0644]
LayoutTests/contentfiltering/block-after-unblock-request.html [new file with mode: 0644]
LayoutTests/contentfiltering/resources/contentfiltering.js
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp
Source/WebCore/loader/ContentFilter.cpp
Source/WebCore/loader/ContentFilter.h
Source/WebCore/loader/DocumentLoader.cpp
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/PolicyChecker.cpp
Source/WebCore/loader/PolicyChecker.h
Source/WebCore/page/Frame.h
Source/WebCore/platform/ContentFilterUnblockHandler.h
Source/WebCore/platform/PlatformContentFilter.h
Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm
Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm
Source/WebCore/testing/MockContentFilter.cpp
Source/WebCore/testing/MockContentFilter.h
Source/WebCore/testing/MockContentFilterSettings.cpp
Source/WebCore/testing/MockContentFilterSettings.h
Source/WebCore/testing/MockContentFilterSettings.idl
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm
Source/WebKit/mac/WebView/WebFrame.mm
Source/WebKit/mac/WebView/WebFrameInternal.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/Cocoa/WebPageProxyCocoa.mm
Source/WebKit2/UIProcess/WebFrameProxy.cpp
Source/WebKit2/UIProcess/WebFrameProxy.h
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp