<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[181791] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/181791">181791</a></dd>
<dt>Author</dt> <dd>aestes@apple.com</dd>
<dt>Date</dt> <dd>2015-03-20 01:42:59 -0700 (Fri, 20 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[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&lt;Frames&gt; 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.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestscontentfilteringresourcescontentfilteringjs">trunk/LayoutTests/contentfiltering/resources/contentfiltering.js</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsjsJSMockContentFilterSettingsCustomcpp">trunk/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderContentFiltercpp">trunk/Source/WebCore/loader/ContentFilter.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderContentFilterh">trunk/Source/WebCore/loader/ContentFilter.h</a></li>
<li><a href="#trunkSourceWebCoreloaderDocumentLoadercpp">trunk/Source/WebCore/loader/DocumentLoader.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderFrameLoadercpp">trunk/Source/WebCore/loader/FrameLoader.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderPolicyCheckercpp">trunk/Source/WebCore/loader/PolicyChecker.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderPolicyCheckerh">trunk/Source/WebCore/loader/PolicyChecker.h</a></li>
<li><a href="#trunkSourceWebCorepageFrameh">trunk/Source/WebCore/page/Frame.h</a></li>
<li><a href="#trunkSourceWebCoreplatformContentFilterUnblockHandlerh">trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h</a></li>
<li><a href="#trunkSourceWebCoreplatformPlatformContentFilterh">trunk/Source/WebCore/platform/PlatformContentFilter.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaContentFilterUnblockHandlerCocoamm">trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaParentalControlsContentFiltermm">trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm</a></li>
<li><a href="#trunkSourceWebCoretestingMockContentFiltercpp">trunk/Source/WebCore/testing/MockContentFilter.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingMockContentFilterh">trunk/Source/WebCore/testing/MockContentFilter.h</a></li>
<li><a href="#trunkSourceWebCoretestingMockContentFilterSettingscpp">trunk/Source/WebCore/testing/MockContentFilterSettings.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingMockContentFilterSettingsh">trunk/Source/WebCore/testing/MockContentFilterSettings.h</a></li>
<li><a href="#trunkSourceWebCoretestingMockContentFilterSettingsidl">trunk/Source/WebCore/testing/MockContentFilterSettings.idl</a></li>
<li><a href="#trunkSourceWebKitmacChangeLog">trunk/Source/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitmacWebCoreSupportWebFrameLoaderClientmm">trunk/Source/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebFramemm">trunk/Source/WebKit/mac/WebView/WebFrame.mm</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebFrameInternalh">trunk/Source/WebKit/mac/WebView/WebFrameInternal.h</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaWebPageProxyCocoamm">trunk/Source/WebKit2/UIProcess/Cocoa/WebPageProxyCocoa.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebFrameProxycpp">trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebFrameProxyh">trunk/Source/WebKit2/UIProcess/WebFrameProxy.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxycpp">trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebCoreSupportWebFrameLoaderClientcpp">trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestscontentfilteringallowafterunblockrequestexpectedhtml">trunk/LayoutTests/contentfiltering/allow-after-unblock-request-expected.html</a></li>
<li><a href="#trunkLayoutTestscontentfilteringallowafterunblockrequesthtml">trunk/LayoutTests/contentfiltering/allow-after-unblock-request.html</a></li>
<li><a href="#trunkLayoutTestscontentfilteringblockafterunblockrequestexpectedhtml">trunk/LayoutTests/contentfiltering/block-after-unblock-request-expected.html</a></li>
<li><a href="#trunkLayoutTestscontentfilteringblockafterunblockrequesthtml">trunk/LayoutTests/contentfiltering/block-after-unblock-request.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/LayoutTests/ChangeLog        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1,5 +1,24 @@
</span><span class="cx"> 2015-03-19  Andy Estes  &lt;aestes@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        [Content Filtering] Add tests for unblock requests
+        https://bugs.webkit.org/show_bug.cgi?id=142900
+
+        Reviewed by Andreas Kling.
+
+        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.
+
+2015-03-19  Andy Estes  &lt;aestes@apple.com&gt;
+
</ins><span class="cx">         [Content Filtering] Give contentfiltering tests a JavaScript harness
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=142899
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestscontentfilteringallowafterunblockrequestexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/contentfiltering/allow-after-unblock-request-expected.html (0 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/contentfiltering/allow-after-unblock-request-expected.html                                (rev 0)
+++ trunk/LayoutTests/contentfiltering/allow-after-unblock-request-expected.html        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;iframe src=&quot;data:text/html,PASS&quot;&gt;&lt;/iframe&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscontentfilteringallowafterunblockrequesthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/contentfiltering/allow-after-unblock-request.html (0 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/contentfiltering/allow-after-unblock-request.html                                (rev 0)
+++ trunk/LayoutTests/contentfiltering/allow-after-unblock-request.html        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;script src=&quot;resources/contentfiltering.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+var internals = window.internals;
+if (internals) {
+    var settings = internals.mockContentFilterSettings;
+    testContentFiltering(/* decisionPoint */settings.DECISION_POINT_AFTER_FINISHED_ADDING_DATA, /* decision */settings.DECISION_ALLOW, /* decideAfterUnblockRequest */true);
+}
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscontentfilteringblockafterunblockrequestexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/contentfiltering/block-after-unblock-request-expected.html (0 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/contentfiltering/block-after-unblock-request-expected.html                                (rev 0)
+++ trunk/LayoutTests/contentfiltering/block-after-unblock-request-expected.html        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;iframe src=&quot;data:text/html,PASS&quot;&gt;&lt;/iframe&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscontentfilteringblockafterunblockrequesthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/contentfiltering/block-after-unblock-request.html (0 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/contentfiltering/block-after-unblock-request.html                                (rev 0)
+++ trunk/LayoutTests/contentfiltering/block-after-unblock-request.html        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;script src=&quot;resources/contentfiltering.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+var internals = window.internals;
+if (internals) {
+    var settings = internals.mockContentFilterSettings;
+    testContentFiltering(/* decisionPoint */settings.DECISION_POINT_AFTER_FINISHED_ADDING_DATA, /* decision */settings.DECISION_BLOCK, /* decideAfterUnblockRequest */true);
+}
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscontentfilteringresourcescontentfilteringjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/contentfiltering/resources/contentfiltering.js (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/contentfiltering/resources/contentfiltering.js        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/LayoutTests/contentfiltering/resources/contentfiltering.js        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1,22 +1,37 @@
</span><del>-function _doTest(decisionPoint, decision)
</del><ins>+function _doTest(decisionPoint, decision, decideAfterUnblockRequest)
</ins><span class="cx"> {
</span><span class="cx">     var settings = window.internals.mockContentFilterSettings;
</span><span class="cx">     settings.enabled = true;
</span><span class="cx">     settings.decisionPoint = decisionPoint;
</span><del>-    settings.decision = decision;
</del><ins>+    settings.decision = (decideAfterUnblockRequest ? settings.DECISION_BLOCK : decision);
</ins><span class="cx">     
</span><span class="cx">     var blockedStringText = (decision === settings.DECISION_ALLOW ? &quot;FAIL&quot; : &quot;PASS&quot;);
</span><del>-    settings.blockedString = &quot;&lt;!DOCTYPE html&gt;&lt;body&gt;&quot; + blockedStringText;
</del><ins>+    if (decideAfterUnblockRequest) {
+        settings.unblockRequestDecision = decision;
+        settings.blockedString = &quot;&lt;!DOCTYPE html&gt;&lt;script&gt;function unblockRequestDenied() { window.top.postMessage('unblockrequestdenied', '*'); }&lt;/script&gt;&lt;body&gt;&quot; + blockedStringText;
+    } else
+        settings.blockedString = &quot;&lt;!DOCTYPE html&gt;&lt;body&gt;&quot; + blockedStringText;
</ins><span class="cx"> 
</span><ins>+    var isUnblocking = false;
</ins><span class="cx">     var iframe = document.createElement(&quot;iframe&quot;);
</span><span class="cx">     document.body.appendChild(iframe);
</span><span class="cx">     iframe.addEventListener(&quot;load&quot;, function(event) {
</span><del>-        window.testRunner.notifyDone();
</del><ins>+        if (isUnblocking || !decideAfterUnblockRequest) {
+            window.testRunner.notifyDone();
+            return;
+        }
+
+        isUnblocking = true;
+        window.addEventListener(&quot;message&quot;, function(event) {
+            if (event.data === &quot;unblockrequestdenied&quot;)
+                window.testRunner.notifyDone();
+        }, false);
+        iframe.contentDocument.location = settings.unblockRequestURL;
</ins><span class="cx">     }, false);
</span><span class="cx">     iframe.src = &quot;data:text/html,&lt;!DOCTYPE html&gt;&lt;body&gt;&quot; + (blockedStringText === &quot;FAIL&quot; ? &quot;PASS&quot; : &quot;FAIL&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function testContentFiltering(decisionPoint, decision)
</del><ins>+function testContentFiltering(decisionPoint, decision, decideAfterUnblockRequest)
</ins><span class="cx"> {
</span><span class="cx">     if (!window.internals) {
</span><span class="cx">         console.log(&quot;This test requires window.internals&quot;);
</span><span class="lines">@@ -30,6 +45,6 @@
</span><span class="cx"> 
</span><span class="cx">     window.testRunner.waitUntilDone();
</span><span class="cx">     window.addEventListener(&quot;load&quot;, function(event) {
</span><del>-        _doTest(decisionPoint, decision);
</del><ins>+        _doTest(decisionPoint, decision, decideAfterUnblockRequest);
</ins><span class="cx">     }, false);
</span><span class="cx"> }
</span><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/ChangeLog        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1,3 +1,99 @@
</span><ins>+2015-03-19  Andy Estes  &lt;aestes@apple.com&gt;
+
+        [Content Filtering] Add tests for unblock requests
+        https://bugs.webkit.org/show_bug.cgi?id=142900
+
+        Reviewed by Andreas Kling.
+
+        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&lt;Frames&gt; 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.
+
</ins><span class="cx"> 2015-03-20  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Crash due to empty drag image during drag-and-drop
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSMockContentFilterSettingsCustomcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -35,6 +35,9 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+using Decision = MockContentFilterSettings::Decision;
+using DecisionPoint = MockContentFilterSettings::DecisionPoint;
+
</ins><span class="cx"> // Must be kept in sync with values in MockContentFilterSettings.idl.
</span><span class="cx"> const uint8_t decisionPointAfterResponse = 0;
</span><span class="cx"> const uint8_t decisionPointAfterAddData = 1;
</span><span class="lines">@@ -42,22 +45,22 @@
</span><span class="cx"> const uint8_t decisionAllow = 0;
</span><span class="cx"> const uint8_t decisionBlock = 1;
</span><span class="cx"> 
</span><del>-JSC::JSValue JSMockContentFilterSettings::decisionPoint(JSC::ExecState*) const
</del><ins>+JSValue JSMockContentFilterSettings::decisionPoint(ExecState*) const
</ins><span class="cx"> {
</span><span class="cx">     switch (impl().decisionPoint()) {
</span><del>-    case MockContentFilterSettings::DecisionPoint::AfterResponse:
</del><ins>+    case DecisionPoint::AfterResponse:
</ins><span class="cx">         return jsNumber(decisionPointAfterResponse);
</span><del>-    case MockContentFilterSettings::DecisionPoint::AfterAddData:
</del><ins>+    case DecisionPoint::AfterAddData:
</ins><span class="cx">         return jsNumber(decisionPointAfterAddData);
</span><del>-    case MockContentFilterSettings::DecisionPoint::AfterFinishedAddingData:
</del><ins>+    case DecisionPoint::AfterFinishedAddingData:
</ins><span class="cx">         return jsNumber(decisionPointAfterFinishedAddingData);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT_NOT_REACHED();
</span><del>-    return { };
</del><ins>+    return jsUndefined();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSMockContentFilterSettings::setDecisionPoint(JSC::ExecState* exec, JSC::JSValue value)
</del><ins>+void JSMockContentFilterSettings::setDecisionPoint(ExecState* exec, JSValue value)
</ins><span class="cx"> {
</span><span class="cx">     uint8_t nativeValue { toUInt8(exec, value, EnforceRange) };
</span><span class="cx">     if (exec-&gt;hadException())
</span><span class="lines">@@ -65,50 +68,77 @@
</span><span class="cx"> 
</span><span class="cx">     switch (nativeValue) {
</span><span class="cx">     case decisionPointAfterResponse:
</span><del>-        impl().setDecisionPoint(MockContentFilterSettings::DecisionPoint::AfterResponse);
</del><ins>+        impl().setDecisionPoint(DecisionPoint::AfterResponse);
</ins><span class="cx">         return;
</span><span class="cx">     case decisionPointAfterAddData:
</span><del>-        impl().setDecisionPoint(MockContentFilterSettings::DecisionPoint::AfterAddData);
</del><ins>+        impl().setDecisionPoint(DecisionPoint::AfterAddData);
</ins><span class="cx">         return;
</span><span class="cx">     case decisionPointAfterFinishedAddingData:
</span><del>-        impl().setDecisionPoint(MockContentFilterSettings::DecisionPoint::AfterFinishedAddingData);
</del><ins>+        impl().setDecisionPoint(DecisionPoint::AfterFinishedAddingData);
</ins><span class="cx">         return;
</span><del>-    default:
-        throwTypeError(exec, String::format(&quot;%u is not a valid decisionPoint value.&quot;, nativeValue));
</del><span class="cx">     }
</span><ins>+
+    throwTypeError(exec, String::format(&quot;%u is not a valid decisionPoint value.&quot;, nativeValue));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSC::JSValue JSMockContentFilterSettings::decision(JSC::ExecState*) const
</del><ins>+static inline JSValue toJSValue(Decision decision)
</ins><span class="cx"> {
</span><del>-    switch (impl().decision()) {
-    case MockContentFilterSettings::Decision::Allow:
</del><ins>+    switch (decision) {
+    case Decision::Allow:
</ins><span class="cx">         return jsNumber(decisionAllow);
</span><del>-    case MockContentFilterSettings::Decision::Block:
</del><ins>+    case Decision::Block:
</ins><span class="cx">         return jsNumber(decisionBlock);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT_NOT_REACHED();
</span><del>-    return { };
</del><ins>+    return jsUndefined();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSMockContentFilterSettings::setDecision(JSC::ExecState* exec, JSC::JSValue value)
</del><ins>+static inline Decision toDecision(ExecState* exec, JSValue value)
</ins><span class="cx"> {
</span><span class="cx">     uint8_t nativeValue { toUInt8(exec, value, EnforceRange) };
</span><span class="cx">     if (exec-&gt;hadException())
</span><del>-        return;
</del><ins>+        return Decision::Allow;
</ins><span class="cx"> 
</span><span class="cx">     switch (nativeValue) {
</span><span class="cx">     case decisionAllow:
</span><del>-        impl().setDecision(MockContentFilterSettings::Decision::Allow);
-        return;
</del><ins>+        return Decision::Allow;
</ins><span class="cx">     case decisionBlock:
</span><del>-        impl().setDecision(MockContentFilterSettings::Decision::Block);
-        return;
-    default:
-        throwTypeError(exec, String::format(&quot;%u is not a valid decision value.&quot;, nativeValue));
</del><ins>+        return Decision::Block;
</ins><span class="cx">     }
</span><ins>+
+    throwTypeError(exec, String::format(&quot;%u is not a valid decision value.&quot;, nativeValue));
+    return Decision::Allow;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSValue JSMockContentFilterSettings::decision(ExecState*) const
+{
+    return toJSValue(impl().decision());
+}
+
+void JSMockContentFilterSettings::setDecision(ExecState* exec, JSValue value)
+{
+    Decision decision { toDecision(exec, value) };
+    if (exec-&gt;hadException())
+        return;
+
+    impl().setDecision(decision);
+}
+
+JSValue JSMockContentFilterSettings::unblockRequestDecision(ExecState*) const
+{
+    return toJSValue(impl().unblockRequestDecision());
+}
+
+void JSMockContentFilterSettings::setUnblockRequestDecision(ExecState* exec, JSValue value)
+{
+    Decision unblockRequestDecision { toDecision(exec, value) };
+    if (exec-&gt;hadException())
+        return;
+
+    impl().setUnblockRequestDecision(unblockRequestDecision);
+}
+
</ins><span class="cx"> }; // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(CONTENT_FILTERING)
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderContentFiltercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ContentFilter.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ContentFilter.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/loader/ContentFilter.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -28,9 +28,14 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><span class="cx"> 
</span><ins>+#include &quot;DocumentLoader.h&quot;
+#include &quot;Frame.h&quot;
</ins><span class="cx"> #include &quot;NetworkExtensionContentFilter.h&quot;
</span><span class="cx"> #include &quot;ParentalControlsContentFilter.h&quot;
</span><ins>+#include &quot;ScriptController.h&quot;
+#include &lt;bindings/ScriptValue.h&gt;
</ins><span class="cx"> #include &lt;wtf/NeverDestroyed.h&gt;
</span><ins>+#include &lt;wtf/Vector.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -47,7 +52,7 @@
</span><span class="cx">     return types;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-std::unique_ptr&lt;ContentFilter&gt; ContentFilter::createIfNeeded(const ResourceResponse&amp; response)
</del><ins>+std::unique_ptr&lt;ContentFilter&gt; ContentFilter::createIfNeeded(const ResourceResponse&amp; response, DocumentLoader&amp; documentLoader)
</ins><span class="cx"> {
</span><span class="cx">     Container filters;
</span><span class="cx">     for (auto&amp; type : types()) {
</span><span class="lines">@@ -58,11 +63,12 @@
</span><span class="cx">     if (filters.isEmpty())
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><del>-    return std::make_unique&lt;ContentFilter&gt;(WTF::move(filters));
</del><ins>+    return std::make_unique&lt;ContentFilter&gt;(WTF::move(filters), documentLoader);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-ContentFilter::ContentFilter(Container contentFilters)
</del><ins>+ContentFilter::ContentFilter(Container contentFilters, DocumentLoader&amp; documentLoader)
</ins><span class="cx">     : m_contentFilters { WTF::move(contentFilters) }
</span><ins>+    , m_documentLoader { documentLoader }
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!m_contentFilters.isEmpty());
</span><span class="cx"> }
</span><span class="lines">@@ -121,13 +127,32 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(didBlockData());
</span><span class="cx"> 
</span><ins>+    PlatformContentFilter* blockingFilter = nullptr;
</ins><span class="cx">     for (auto&amp; contentFilter : m_contentFilters) {
</span><del>-        if (contentFilter-&gt;didBlockData())
-            return contentFilter-&gt;unblockHandler();
</del><ins>+        if (contentFilter-&gt;didBlockData()) {
+            blockingFilter = contentFilter.get();
+            break;
+        }
</ins><span class="cx">     }
</span><ins>+    ASSERT(blockingFilter);
</ins><span class="cx"> 
</span><del>-    ASSERT_NOT_REACHED();
-    return { };
</del><ins>+    StringCapture unblockRequestDeniedScript { blockingFilter-&gt;unblockRequestDeniedScript() };
+    if (unblockRequestDeniedScript.string().isEmpty())
+        return blockingFilter-&gt;unblockHandler();
+
+    // It would be a layering violation for the unblock handler to access its frame,
+    // so we will execute the unblock denied script on its behalf.
+    ContentFilterUnblockHandler unblockHandler { blockingFilter-&gt;unblockHandler() };
+    RefPtr&lt;Frame&gt; frame { m_documentLoader.frame() };
+    return ContentFilterUnblockHandler {
+        unblockHandler.unblockURLHost(), [unblockHandler, frame, unblockRequestDeniedScript](ContentFilterUnblockHandler::DecisionHandlerFunction decisionHandler) {
+            unblockHandler.requestUnblockAsync([decisionHandler, frame, unblockRequestDeniedScript](bool unblocked) {
+                decisionHandler(unblocked);
+                if (!unblocked &amp;&amp; frame)
+                    frame-&gt;script().executeScript(unblockRequestDeniedScript.string());
+            });
+        }
+    };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ContentFilter.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ContentFilter.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/loader/ContentFilter.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -33,12 +33,13 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+class DocumentLoader;
</ins><span class="cx"> class ResourceResponse;
</span><span class="cx"> 
</span><span class="cx"> class ContentFilter final : public PlatformContentFilter {
</span><span class="cx"> public:
</span><span class="cx">     template &lt;typename T&gt; static void addType() { types().append(type&lt;T&gt;()); }
</span><del>-    static std::unique_ptr&lt;ContentFilter&gt; createIfNeeded(const ResourceResponse&amp;);
</del><ins>+    static std::unique_ptr&lt;ContentFilter&gt; createIfNeeded(const ResourceResponse&amp;, DocumentLoader&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void addData(const char* data, int length) override;
</span><span class="cx">     void finishedAddingData() override;
</span><span class="lines">@@ -56,10 +57,11 @@
</span><span class="cx">     WEBCORE_EXPORT static Vector&lt;Type&gt;&amp; types();
</span><span class="cx"> 
</span><span class="cx">     using Container = Vector&lt;std::unique_ptr&lt;PlatformContentFilter&gt;&gt;;
</span><del>-    friend std::unique_ptr&lt;ContentFilter&gt; std::make_unique&lt;ContentFilter&gt;(Container&amp;&amp;);
-    explicit ContentFilter(Container);
</del><ins>+    friend std::unique_ptr&lt;ContentFilter&gt; std::make_unique&lt;ContentFilter&gt;(Container&amp;&amp;, DocumentLoader&amp;);
+    explicit ContentFilter(Container, DocumentLoader&amp;);
</ins><span class="cx"> 
</span><span class="cx">     Container m_contentFilters;
</span><ins>+    DocumentLoader&amp; m_documentLoader;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T&gt;
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderDocumentLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/DocumentLoader.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -663,7 +663,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    m_contentFilter = ContentFilter::createIfNeeded(response);
</del><ins>+    m_contentFilter = ContentFilter::createIfNeeded(response, *this);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     frameLoader()-&gt;policyChecker().checkContentPolicy(m_response, [this](PolicyAction policy) {
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderFrameLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/FrameLoader.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1124,6 +1124,7 @@
</span><span class="cx"> 
</span><span class="cx"> void FrameLoader::prepareForLoadStart()
</span><span class="cx"> {
</span><ins>+    policyChecker().prepareForLoadStart();
</ins><span class="cx">     m_progressTracker-&gt;progressStarted();
</span><span class="cx">     m_client.dispatchDidStartProvisionalLoad();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderPolicyCheckercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/PolicyChecker.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/PolicyChecker.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/loader/PolicyChecker.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -56,6 +56,13 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PolicyChecker::prepareForLoadStart()
+{
+#if ENABLE(CONTENT_FILTERING)
+    m_contentFilterUnblockHandler = { };
+#endif
+}
+
</ins><span class="cx"> void PolicyChecker::checkNavigationPolicy(const ResourceRequest&amp; newRequest, NavigationPolicyDecisionFunction function)
</span><span class="cx"> {
</span><span class="cx">     checkNavigationPolicy(newRequest, m_frame.loader().activeDocumentLoader(), nullptr, WTF::move(function));
</span><span class="lines">@@ -105,6 +112,17 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilterUnblockHandler.canHandleRequest(request)) {
+        RefPtr&lt;Frame&gt; frame { &amp;m_frame };
+        m_contentFilterUnblockHandler.requestUnblockAsync([frame](bool unblocked) {
+            if (unblocked)
+                frame-&gt;loader().reload();
+        });
+        continueAfterNavigationPolicy(PolicyIgnore);
+    }
+#endif
+
</ins><span class="cx">     m_delegateIsDecidingNavigationPolicy = true;
</span><span class="cx">     m_frame.loader().client().dispatchDecidePolicyForNavigationAction(action, request, formState, [this](PolicyAction action) {
</span><span class="cx">         continueAfterNavigationPolicy(action);
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderPolicyCheckerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/PolicyChecker.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/PolicyChecker.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/loader/PolicyChecker.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -36,6 +36,10 @@
</span><span class="cx"> #include &lt;wtf/PassRefPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/text/WTFString.h&gt;
</span><span class="cx"> 
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+#include &quot;ContentFilterUnblockHandler.h&quot;
+#endif
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class DocumentLoader;
</span><span class="lines">@@ -50,6 +54,7 @@
</span><span class="cx"> public:
</span><span class="cx">     explicit PolicyChecker(Frame&amp;);
</span><span class="cx"> 
</span><ins>+    void prepareForLoadStart();
</ins><span class="cx">     void checkNavigationPolicy(const ResourceRequest&amp;, DocumentLoader*, PassRefPtr&lt;FormState&gt;, NavigationPolicyDecisionFunction);
</span><span class="cx">     void checkNavigationPolicy(const ResourceRequest&amp;, NavigationPolicyDecisionFunction);
</span><span class="cx">     void checkNewWindowPolicy(const NavigationAction&amp;, const ResourceRequest&amp;, PassRefPtr&lt;FormState&gt;, const String&amp; frameName, NewWindowPolicyDecisionFunction);
</span><span class="lines">@@ -74,6 +79,10 @@
</span><span class="cx">     // the heart to hack on all the platforms to make that happen right now.
</span><span class="cx">     void continueLoadAfterWillSubmitForm(PolicyAction);
</span><span class="cx"> 
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+    void setContentFilterUnblockHandler(ContentFilterUnblockHandler unblockHandler) { m_contentFilterUnblockHandler = WTF::move(unblockHandler); }
+#endif
+
</ins><span class="cx"> private:
</span><span class="cx">     void continueAfterNavigationPolicy(PolicyAction);
</span><span class="cx">     void continueAfterNewWindowPolicy(PolicyAction);
</span><span class="lines">@@ -91,6 +100,10 @@
</span><span class="cx">     // on navigation action delegate callbacks.
</span><span class="cx">     FrameLoadType m_loadType;
</span><span class="cx">     PolicyCallback m_callback;
</span><ins>+
+#if ENABLE(CONTENT_FILTERING)
+    ContentFilterUnblockHandler m_contentFilterUnblockHandler;
+#endif
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Frame.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Frame.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/page/Frame.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> #include &quot;ScrollTypes.h&quot;
</span><span class="cx"> #include &quot;UserScriptTypes.h&quot;
</span><span class="cx"> #include &lt;memory&gt;
</span><del>-#include &lt;wtf/RefCounted.h&gt;
</del><ins>+#include &lt;wtf/ThreadSafeRefCounted.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> #include &quot;ViewportArguments.h&quot;
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx">     };
</span><span class="cx">     typedef unsigned LayerTreeFlags;
</span><span class="cx"> 
</span><del>-    class Frame : public RefCounted&lt;Frame&gt; {
</del><ins>+    class Frame : public ThreadSafeRefCounted&lt;Frame&gt; {
</ins><span class="cx">     public:
</span><span class="cx">         WEBCORE_EXPORT static Ref&lt;Frame&gt; create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformContentFilterUnblockHandlerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -30,10 +30,13 @@
</span><span class="cx"> 
</span><span class="cx"> #include &lt;functional&gt;
</span><span class="cx"> #include &lt;wtf/RetainPtr.h&gt;
</span><ins>+#include &lt;wtf/text/WTFString.h&gt;
</ins><span class="cx"> 
</span><del>-OBJC_CLASS NSKeyedArchiver;
-OBJC_CLASS NSKeyedUnarchiver;
</del><ins>+OBJC_CLASS NSCoder;
+
+#if PLATFORM(IOS)
</ins><span class="cx"> OBJC_CLASS WebFilterEvaluator;
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -41,19 +44,31 @@
</span><span class="cx"> 
</span><span class="cx"> class ContentFilterUnblockHandler {
</span><span class="cx"> public:
</span><del>-    ContentFilterUnblockHandler() = default;
-    explicit ContentFilterUnblockHandler(WebFilterEvaluator *evaluator) : m_webFilterEvaluator { evaluator } { }
</del><ins>+    using DecisionHandlerFunction = std::function&lt;void(bool unblocked)&gt;;
+    using UnblockRequesterFunction = std::function&lt;void(DecisionHandlerFunction)&gt;;
</ins><span class="cx"> 
</span><del>-    void clear() { m_webFilterEvaluator = nullptr; }
-    WEBCORE_EXPORT void encode(NSKeyedArchiver *) const;
-    WEBCORE_EXPORT static bool decode(NSKeyedUnarchiver *, ContentFilterUnblockHandler&amp;);
</del><ins>+    static const char* unblockURLScheme() { return &quot;x-apple-content-filter&quot;; }
</ins><span class="cx"> 
</span><ins>+    ContentFilterUnblockHandler() = default;
+    WEBCORE_EXPORT ContentFilterUnblockHandler(String unblockURLHost, UnblockRequesterFunction);
</ins><span class="cx"> #if PLATFORM(IOS)
</span><del>-    WEBCORE_EXPORT bool handleUnblockRequestAndDispatchIfSuccessful(const ResourceRequest&amp;, std::function&lt;void()&gt;);
</del><ins>+    ContentFilterUnblockHandler(String unblockURLHost, RetainPtr&lt;WebFilterEvaluator&gt;);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    WEBCORE_EXPORT bool needsUIProcess() const;
+    WEBCORE_EXPORT void encode(NSCoder *) const;
+    WEBCORE_EXPORT static bool decode(NSCoder *, ContentFilterUnblockHandler&amp;);
+    WEBCORE_EXPORT bool canHandleRequest(const ResourceRequest&amp;) const;
+    WEBCORE_EXPORT void requestUnblockAsync(DecisionHandlerFunction) const;
+
+    const String&amp; unblockURLHost() const { return m_unblockURLHost; }
+
</ins><span class="cx"> private:
</span><ins>+    String m_unblockURLHost;
+    UnblockRequesterFunction m_unblockRequester;
+#if PLATFORM(IOS)
</ins><span class="cx">     RetainPtr&lt;WebFilterEvaluator&gt; m_webFilterEvaluator;
</span><ins>+#endif
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformPlatformContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/PlatformContentFilter.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/PlatformContentFilter.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/platform/PlatformContentFilter.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx">     virtual bool didBlockData() const = 0;
</span><span class="cx">     virtual const char* getReplacementData(int&amp; length) const = 0;
</span><span class="cx">     virtual ContentFilterUnblockHandler unblockHandler() const = 0;
</span><ins>+    virtual String unblockRequestDeniedScript() const { return emptyString(); }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaContentFilterUnblockHandlerCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -28,62 +28,118 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><span class="cx"> 
</span><ins>+#import &quot;BlockExceptions.h&quot;
</ins><span class="cx"> #import &quot;ResourceRequest.h&quot;
</span><ins>+
+#if PLATFORM(IOS)
</ins><span class="cx"> #import &quot;SoftLinking.h&quot;
</span><ins>+#import &quot;WebCoreThreadRun.h&quot;
</ins><span class="cx"> #import &quot;WebFilterEvaluatorSPI.h&quot;
</span><del>-#import &lt;objc/runtime.h&gt;
</del><span class="cx"> 
</span><span class="cx"> SOFT_LINK_PRIVATE_FRAMEWORK(WebContentAnalysis);
</span><span class="cx"> SOFT_LINK_CLASS(WebContentAnalysis, WebFilterEvaluator);
</span><span class="cx"> 
</span><ins>+static NSString * const webFilterEvaluatorKey { @&quot;webFilterEvaluator&quot; };
+#endif
+
+static NSString * const unblockURLHostKey { @&quot;unblockURLHost&quot; };
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-static NSString * const platformContentFilterKey = @&quot;platformContentFilter&quot;;
</del><ins>+ContentFilterUnblockHandler::ContentFilterUnblockHandler(String unblockURLHost, UnblockRequesterFunction unblockRequester)
+    : m_unblockURLHost { WTF::move(unblockURLHost) }
+    , m_unblockRequester { WTF::move(unblockRequester) }
+{
+}
</ins><span class="cx"> 
</span><del>-void ContentFilterUnblockHandler::encode(NSKeyedArchiver *archiver) const
</del><ins>+#if PLATFORM(IOS)
+ContentFilterUnblockHandler::ContentFilterUnblockHandler(String unblockURLHost, RetainPtr&lt;WebFilterEvaluator&gt; evaluator)
+    : m_unblockURLHost { WTF::move(unblockURLHost) }
+    , m_webFilterEvaluator { WTF::move(evaluator) }
</ins><span class="cx"> {
</span><del>-    if ([getWebFilterEvaluatorClass() conformsToProtocol:@protocol(NSSecureCoding)])
-        [archiver encodeObject:m_webFilterEvaluator.get() forKey:platformContentFilterKey];
</del><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><del>-bool ContentFilterUnblockHandler::decode(NSKeyedUnarchiver *unarchiver, ContentFilterUnblockHandler&amp; unblockHandler)
</del><ins>+bool ContentFilterUnblockHandler::needsUIProcess() const
</ins><span class="cx"> {
</span><del>-    @try {
-        if ([getWebFilterEvaluatorClass() conformsToProtocol:@protocol(NSSecureCoding)])
-            unblockHandler.m_webFilterEvaluator = (WebFilterEvaluator *)[unarchiver decodeObjectOfClass:getWebFilterEvaluatorClass() forKey:platformContentFilterKey];
-        return true;
-    } @catch (NSException *exception) {
-        LOG_ERROR(&quot;The platform content filter being decoded is not a WebFilterEvaluator.&quot;);
-    }
-    
</del><ins>+#if PLATFORM(IOS)
+    return m_webFilterEvaluator;
+#else
</ins><span class="cx">     return false;
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ContentFilterUnblockHandler::encode(NSCoder *coder) const
+{
+    ASSERT_ARG(coder, coder.allowsKeyedCoding &amp;&amp; coder.requiresSecureCoding);
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    [coder encodeObject:m_unblockURLHost forKey:unblockURLHostKey];
</ins><span class="cx"> #if PLATFORM(IOS)
</span><del>-static inline const char* scheme()
</del><ins>+    [coder encodeObject:m_webFilterEvaluator.get() forKey:webFilterEvaluatorKey];
+#endif
+    END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+bool ContentFilterUnblockHandler::decode(NSCoder *coder, ContentFilterUnblockHandler&amp; unblockHandler)
</ins><span class="cx"> {
</span><del>-    return &quot;x-apple-content-filter&quot;;
</del><ins>+    ASSERT_ARG(coder, coder.allowsKeyedCoding &amp;&amp; coder.requiresSecureCoding);
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    unblockHandler.m_unblockURLHost = [coder decodeObjectOfClass:[NSString class] forKey:unblockURLHostKey];
+#if PLATFORM(IOS)
+    unblockHandler.m_webFilterEvaluator = [coder decodeObjectOfClass:getWebFilterEvaluatorClass() forKey:webFilterEvaluatorKey];
+#endif
+    return true;
+    END_BLOCK_OBJC_EXCEPTIONS;
+    return false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ContentFilterUnblockHandler::handleUnblockRequestAndDispatchIfSuccessful(const ResourceRequest&amp; request, std::function&lt;void()&gt; function)
</del><ins>+bool ContentFilterUnblockHandler::canHandleRequest(const ResourceRequest&amp; request) const
</ins><span class="cx"> {
</span><del>-    if (!m_webFilterEvaluator)
</del><ins>+    if (!m_unblockRequester) {
+#if PLATFORM(IOS)
+        if (!m_webFilterEvaluator)
+            return false;
+#else
</ins><span class="cx">         return false;
</span><ins>+#endif
+    }
</ins><span class="cx"> 
</span><del>-    if (!request.url().protocolIs(scheme()))
-        return false;
</del><ins>+    return request.url().protocolIs(unblockURLScheme()) &amp;&amp; equalIgnoringCase(request.url().host(), m_unblockURLHost);
+}
</ins><span class="cx"> 
</span><del>-    if (!equalIgnoringCase(request.url().host(), &quot;unblock&quot;))
-        return false;
</del><ins>+static inline void dispatchToMainThread(void (^block)())
+{
+    dispatch_async(dispatch_get_main_queue(), ^{
+#if PLATFORM(IOS)
+        WebThreadRun(block);
+#else
+        block();
+#endif
+    });
+}
</ins><span class="cx"> 
</span><del>-    [m_webFilterEvaluator unblockWithCompletion:^(BOOL unblocked, NSError *) {
-        if (unblocked)
-            function();
-    }];
-    return true;
-}
</del><ins>+void ContentFilterUnblockHandler::requestUnblockAsync(DecisionHandlerFunction decisionHandler) const
+{
+#if PLATFORM(IOS)
+    if (m_webFilterEvaluator) {
+        [m_webFilterEvaluator unblockWithCompletion:[decisionHandler](BOOL unblocked, NSError *) {
+            dispatchToMainThread([decisionHandler, unblocked] {
+                decisionHandler(unblocked);
+            });
+        }];
+        return;
+    }
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (m_unblockRequester) {
+        m_unblockRequester([decisionHandler](bool unblocked) {
+            dispatchToMainThread([decisionHandler, unblocked] {
+                decisionHandler(unblocked);
+            });
+        });
+    }
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // PLATFORM(IOS) &amp;&amp; ENABLE(CONTENT_FILTERING)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaParentalControlsContentFiltermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -93,7 +93,11 @@
</span><span class="cx"> 
</span><span class="cx"> ContentFilterUnblockHandler ParentalControlsContentFilter::unblockHandler() const
</span><span class="cx"> {
</span><del>-    return ContentFilterUnblockHandler { m_webFilterEvaluator.get() };
</del><ins>+#if PLATFORM(IOS)
+    return ContentFilterUnblockHandler { &quot;unblock&quot;, m_webFilterEvaluator };
+#else
+    return { };
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFiltercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilter.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilter.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/testing/MockContentFilter.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -34,6 +34,9 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+using Decision = MockContentFilterSettings::Decision;
+using DecisionPoint = MockContentFilterSettings::DecisionPoint;
+
</ins><span class="cx"> void MockContentFilter::ensureInstalled()
</span><span class="cx"> {
</span><span class="cx">     static std::once_flag onceFlag;
</span><span class="lines">@@ -42,9 +45,14 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline MockContentFilterSettings&amp; settings()
+{
+    return MockContentFilterSettings::singleton();
+}
+
</ins><span class="cx"> bool MockContentFilter::canHandleResponse(const ResourceResponse&amp;)
</span><span class="cx"> {
</span><del>-    return MockContentFilterSettings::singleton().enabled();
</del><ins>+    return settings().enabled();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> std::unique_ptr&lt;MockContentFilter&gt; MockContentFilter::create(const ResourceResponse&amp; response)
</span><span class="lines">@@ -54,18 +62,18 @@
</span><span class="cx"> 
</span><span class="cx"> MockContentFilter::MockContentFilter(const ResourceResponse&amp;)
</span><span class="cx"> {
</span><del>-    maybeDetermineStatus(MockContentFilterSettings::DecisionPoint::AfterResponse);
</del><ins>+    maybeDetermineStatus(DecisionPoint::AfterResponse);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MockContentFilter::addData(const char* data, int length)
</span><span class="cx"> {
</span><span class="cx">     m_replacementData.append(data, length);
</span><del>-    maybeDetermineStatus(MockContentFilterSettings::DecisionPoint::AfterAddData);
</del><ins>+    maybeDetermineStatus(DecisionPoint::AfterAddData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MockContentFilter::finishedAddingData()
</span><span class="cx"> {
</span><del>-    maybeDetermineStatus(MockContentFilterSettings::DecisionPoint::AfterFinishedAddingData);
</del><ins>+    maybeDetermineStatus(DecisionPoint::AfterFinishedAddingData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool MockContentFilter::needsMoreData() const
</span><span class="lines">@@ -86,20 +94,34 @@
</span><span class="cx"> 
</span><span class="cx"> ContentFilterUnblockHandler MockContentFilter::unblockHandler() const
</span><span class="cx"> {
</span><del>-    return { };
</del><ins>+    using DecisionHandlerFunction = ContentFilterUnblockHandler::DecisionHandlerFunction;
+
+    return ContentFilterUnblockHandler {
+        MockContentFilterSettings::unblockURLHost(), [](DecisionHandlerFunction decisionHandler) {
+            bool shouldAllow { settings().unblockRequestDecision() == Decision::Allow };
+            if (shouldAllow)
+                settings().setDecision(Decision::Allow);
+            decisionHandler(shouldAllow);
+        }
+    };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MockContentFilter::maybeDetermineStatus(MockContentFilterSettings::DecisionPoint decisionPoint)
</del><ins>+String MockContentFilter::unblockRequestDeniedScript() const
</ins><span class="cx"> {
</span><del>-    if (m_status != Status::NeedsMoreData || decisionPoint != MockContentFilterSettings::singleton().decisionPoint())
</del><ins>+    return ASCIILiteral(&quot;unblockRequestDenied()&quot;);
+}
+
+void MockContentFilter::maybeDetermineStatus(DecisionPoint decisionPoint)
+{
+    if (m_status != Status::NeedsMoreData || decisionPoint != settings().decisionPoint())
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    m_status = MockContentFilterSettings::singleton().decision() == MockContentFilterSettings::Decision::Allow ? Status::Allowed : Status::Blocked;
</del><ins>+    m_status = settings().decision() == Decision::Allow ? Status::Allowed : Status::Blocked;
</ins><span class="cx">     if (m_status != Status::Blocked)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_replacementData.clear();
</span><del>-    const CString utf8BlockedString = MockContentFilterSettings::singleton().blockedString().utf8();
</del><ins>+    const CString utf8BlockedString = settings().blockedString().utf8();
</ins><span class="cx">     m_replacementData.append(utf8BlockedString.data(), utf8BlockedString.length());
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilter.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilter.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/testing/MockContentFilter.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -45,6 +45,7 @@
</span><span class="cx">     bool didBlockData() const override;
</span><span class="cx">     const char* getReplacementData(int&amp; length) const override;
</span><span class="cx">     ContentFilterUnblockHandler unblockHandler() const override;
</span><ins>+    String unblockRequestDeniedScript() const override;
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     enum class Status {
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFilterSettingscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilterSettings.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilterSettings.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/testing/MockContentFilterSettings.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -28,6 +28,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><span class="cx"> 
</span><ins>+#include &quot;ContentFilterUnblockHandler.h&quot;
+#include &lt;mutex&gt;
</ins><span class="cx"> #include &lt;wtf/NeverDestroyed.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -43,6 +45,18 @@
</span><span class="cx">     singleton() = MockContentFilterSettings();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+const String&amp; MockContentFilterSettings::unblockRequestURL() const
+{
+    static LazyNeverDestroyed&lt;String&gt; unblockRequestURL;
+    static std::once_flag onceFlag;
+    std::call_once(onceFlag, [] {
+        unblockRequestURL.construct(ContentFilterUnblockHandler::unblockURLScheme());
+        unblockRequestURL.get().append(&quot;://&quot;);
+        unblockRequestURL.get().append(unblockURLHost());
+    });
+    return unblockRequestURL;
+}
+
</ins><span class="cx"> }; // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(CONTENT_FILTERING)
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFilterSettingsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilterSettings.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilterSettings.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/testing/MockContentFilterSettings.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -32,8 +32,8 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class MockContentFilterSettings {
</span><del>-    WTF_MAKE_FAST_ALLOCATED;
</del><span class="cx">     friend class NeverDestroyed&lt;MockContentFilterSettings&gt;;
</span><ins>+
</ins><span class="cx"> public:
</span><span class="cx">     enum class DecisionPoint {
</span><span class="cx">         AfterResponse,
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx"> 
</span><span class="cx">     static MockContentFilterSettings&amp; singleton();
</span><span class="cx">     static void reset();
</span><ins>+    static const char* unblockURLHost() { return &quot;mock-unblock&quot;; }
</ins><span class="cx"> 
</span><span class="cx">     // Trick the generated bindings into thinking we're RefCounted.
</span><span class="cx">     void ref() { }
</span><span class="lines">@@ -65,6 +66,11 @@
</span><span class="cx">     Decision decision() const { return m_decision; }
</span><span class="cx">     void setDecision(Decision decision) { m_decision = decision; }
</span><span class="cx"> 
</span><ins>+    Decision unblockRequestDecision() const { return m_unblockRequestDecision; }
+    void setUnblockRequestDecision(Decision unblockRequestDecision) { m_unblockRequestDecision = unblockRequestDecision; }
+
+    const String&amp; unblockRequestURL() const;
+
</ins><span class="cx"> private:
</span><span class="cx">     MockContentFilterSettings() = default;
</span><span class="cx">     MockContentFilterSettings(const MockContentFilterSettings&amp;) = delete;
</span><span class="lines">@@ -73,6 +79,7 @@
</span><span class="cx">     bool m_enabled { false };
</span><span class="cx">     DecisionPoint m_decisionPoint { DecisionPoint::AfterResponse };
</span><span class="cx">     Decision m_decision { Decision::Allow };
</span><ins>+    Decision m_unblockRequestDecision { Decision::Block };
</ins><span class="cx">     String m_blockedString;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFilterSettingsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilterSettings.idl (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilterSettings.idl        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebCore/testing/MockContentFilterSettings.idl        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -39,4 +39,7 @@
</span><span class="cx">     const octet DECISION_ALLOW = 0;
</span><span class="cx">     const octet DECISION_BLOCK = 1;
</span><span class="cx">     [Custom] attribute octet decision;
</span><ins>+    [Custom] attribute octet unblockRequestDecision;
+
+    readonly attribute DOMString unblockRequestURL;
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/ChangeLog (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/ChangeLog        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit/mac/ChangeLog        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2015-03-19  Andy Estes  &lt;aestes@apple.com&gt;
+
+        [Content Filtering] Add tests for unblock requests
+        https://bugs.webkit.org/show_bug.cgi?id=142900
+
+        Reviewed by Andreas Kling.
+
+        * 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.
+
</ins><span class="cx"> 2015-03-19  Enrica Casucci  &lt;enrica@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;attachment&gt; should put URLs on the pasteboard so that Finder can accept drops.
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebCoreSupportWebFrameLoaderClientmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -151,6 +151,10 @@
</span><span class="cx"> #import &lt;WebCore/RuntimeApplicationChecksIOS.h&gt;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+#import &lt;WebCore/PolicyChecker.h&gt;
+#endif
+
</ins><span class="cx"> using namespace WebCore;
</span><span class="cx"> using namespace HTMLNames;
</span><span class="cx"> 
</span><span class="lines">@@ -665,7 +669,6 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_webFrame-&gt;_private-&gt;provisionalURL);
</span><span class="cx">     m_webFrame-&gt;_private-&gt;provisionalURL = core(m_webFrame.get())-&gt;loader().provisionalDocumentLoader()-&gt;url().string();
</span><del>-    m_webFrame-&gt;_private-&gt;contentFilterUnblockHandler.clear();
</del><span class="cx"> 
</span><span class="cx">     WebView *webView = getWebView(m_webFrame.get());
</span><span class="cx"> #if !PLATFORM(IOS)
</span><span class="lines">@@ -880,11 +883,6 @@
</span><span class="cx"> 
</span><span class="cx"> void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const NavigationAction&amp; action, const ResourceRequest&amp; request, PassRefPtr&lt;FormState&gt; formState, FramePolicyFunction function)
</span><span class="cx"> {
</span><del>-    if ([m_webFrame _contentFilterDidHandleNavigationAction:request]) {
-        function(PolicyIgnore);
-        return;
-    }
-
</del><span class="cx">     WebView *webView = getWebView(m_webFrame.get());
</span><span class="cx">     [[webView _policyDelegateForwarder] webView:webView
</span><span class="cx">                 decidePolicyForNavigationAction:actionDictionary(action, formState)
</span><span class="lines">@@ -2242,10 +2240,12 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if ENABLE(CONTENT_FILTERING)
</ins><span class="cx"> void WebFrameLoaderClient::contentFilterDidBlockLoad(WebCore::ContentFilterUnblockHandler unblockHandler)
</span><span class="cx"> {
</span><del>-    m_webFrame-&gt;_private-&gt;contentFilterUnblockHandler = WTF::move(unblockHandler);
</del><ins>+    core(m_webFrame.get())-&gt;loader().policyChecker().setContentFilterUnblockHandler(WTF::move(unblockHandler));
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> @implementation WebFramePolicyListener
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebFramemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebFrame.mm (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebFrame.mm        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit/mac/WebView/WebFrame.mm        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1002,20 +1002,6 @@
</span><span class="cx">     _private-&gt;coreFrame-&gt;loader().documentLoader()-&gt;commitData((const char *)[data bytes], [data length]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (BOOL)_contentFilterDidHandleNavigationAction:(const WebCore::ResourceRequest &amp;)request
-{
-#if PLATFORM(IOS)
-    RetainPtr&lt;WebFrame&gt; retainedMainFrame = [[self webView] mainFrame];
-    return _private-&gt;contentFilterUnblockHandler.handleUnblockRequestAndDispatchIfSuccessful(request, [retainedMainFrame] {
-        WebThreadRun(^ {
-            [retainedMainFrame reload];
-        });
-    });
-#else
-    return NO;
-#endif
-}
-
</del><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation WebFrame (WebPrivate)
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebFrameInternalh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebFrameInternal.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebFrameInternal.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit/mac/WebView/WebFrameInternal.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -30,7 +30,6 @@
</span><span class="cx"> 
</span><span class="cx"> #import &quot;WebFramePrivate.h&quot;
</span><span class="cx"> #import &quot;WebPreferencesPrivate.h&quot;
</span><del>-#import &lt;WebCore/ContentFilterUnblockHandler.h&gt;
</del><span class="cx"> #import &lt;WebCore/EditAction.h&gt;
</span><span class="cx"> #import &lt;WebCore/FrameLoaderTypes.h&gt;
</span><span class="cx"> #import &lt;WebCore/FrameSelection.h&gt;
</span><span class="lines">@@ -92,7 +91,6 @@
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     BOOL isCommitting;
</span><span class="cx"> #endif
</span><del>-    WebCore::ContentFilterUnblockHandler contentFilterUnblockHandler;
</del><span class="cx"> }
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="lines">@@ -184,8 +182,6 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)_commitData:(NSData *)data;
</span><span class="cx"> 
</span><del>-- (BOOL)_contentFilterDidHandleNavigationAction:(const WebCore::ResourceRequest&amp;)request;
-
</del><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @interface NSObject (WebInternalFrameLoadDelegate)
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit2/ChangeLog        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2015-03-19  Andy Estes  &lt;aestes@apple.com&gt;
+
+        [Content Filtering] Add tests for unblock requests
+        https://bugs.webkit.org/show_bug.cgi?id=142900
+
+        Reviewed by Andreas Kling.
+
+        * 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.
+
</ins><span class="cx"> 2015-03-20  Zan Dobersek  &lt;zdobersek@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Properly guard X11-specific code in BackingStore::createBackend()
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebPageProxyCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPageProxyCocoa.mm (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPageProxyCocoa.mm        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPageProxyCocoa.mm        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -75,7 +75,7 @@
</span><span class="cx"> void WebPageProxy::contentFilterDidBlockLoadForFrame(const WebCore::ContentFilterUnblockHandler&amp; unblockHandler, uint64_t frameID)
</span><span class="cx"> {
</span><span class="cx">     if (WebFrameProxy* frame = m_process-&gt;webFrame(frameID))
</span><del>-        frame-&gt;setContentFilterUnblockHandler(unblockHandler);
</del><ins>+        frame-&gt;contentFilterDidBlockLoad(unblockHandler);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebFrameProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -128,7 +128,7 @@
</span><span class="cx"> {
</span><span class="cx">     m_frameLoadState.didStartProvisionalLoad(url);
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    m_contentFilterUnblockHandler.clear();
</del><ins>+    m_contentFilterUnblockHandler = { };
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -234,16 +234,18 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-bool WebFrameProxy::contentFilterDidHandleNavigationAction(const WebCore::ResourceRequest&amp; request)
</del><ins>+bool WebFrameProxy::didHandleContentFilterUnblockNavigation(const WebCore::ResourceRequest&amp; request)
</ins><span class="cx"> {
</span><del>-#if PLATFORM(IOS)
-    RefPtr&lt;WebPageProxy&gt; retainedPage = m_page;
-    return m_contentFilterUnblockHandler.handleUnblockRequestAndDispatchIfSuccessful(request, [retainedPage] {
-        retainedPage-&gt;reload(false);
</del><ins>+    if (!m_contentFilterUnblockHandler.canHandleRequest(request))
+        return false;
+
+    RefPtr&lt;WebPageProxy&gt; page { m_page };
+    ASSERT(page);
+    m_contentFilterUnblockHandler.requestUnblockAsync([page](bool unblocked) {
+        if (unblocked)
+            page-&gt;reload(false);
</ins><span class="cx">     });
</span><del>-#else
-    return false;
-#endif
</del><ins>+    return true;
</ins><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebFrameProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebFrameProxy.h (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebFrameProxy.h        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit2/UIProcess/WebFrameProxy.h        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -123,8 +123,8 @@
</span><span class="cx">     WebFormSubmissionListenerProxy&amp; setUpFormSubmissionListenerProxy(uint64_t listenerID);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    void setContentFilterUnblockHandler(WebCore::ContentFilterUnblockHandler contentFilterUnblockHandler) { m_contentFilterUnblockHandler = WTF::move(contentFilterUnblockHandler); }
-    bool contentFilterDidHandleNavigationAction(const WebCore::ResourceRequest&amp;);
</del><ins>+    void contentFilterDidBlockLoad(WebCore::ContentFilterUnblockHandler contentFilterUnblockHandler) { m_contentFilterUnblockHandler = WTF::move(contentFilterUnblockHandler); }
+    bool didHandleContentFilterUnblockNavigation(const WebCore::ResourceRequest&amp;);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -3092,7 +3092,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    if (frame-&gt;contentFilterDidHandleNavigationAction(request)) {
</del><ins>+    if (frame-&gt;didHandleContentFilterUnblockNavigation(request)) {
</ins><span class="cx">         receivedPolicyAction = true;
</span><span class="cx">         policyAction = PolicyIgnore;
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebCoreSupportWebFrameLoaderClientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp (181790 => 181791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp        2015-03-20 08:35:33 UTC (rev 181790)
+++ trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp        2015-03-20 08:42:59 UTC (rev 181791)
</span><span class="lines">@@ -1648,7 +1648,12 @@
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><span class="cx"> void WebFrameLoaderClient::contentFilterDidBlockLoad(WebCore::ContentFilterUnblockHandler unblockHandler)
</span><span class="cx"> {
</span><del>-    if (WebPage* webPage = m_frame-&gt;page())
</del><ins>+    if (!unblockHandler.needsUIProcess()) {
+        m_frame-&gt;coreFrame()-&gt;loader().policyChecker().setContentFilterUnblockHandler(WTF::move(unblockHandler));
+        return;
+    }
+
+    if (WebPage* webPage { m_frame-&gt;page() })
</ins><span class="cx">         webPage-&gt;send(Messages::WebPageProxy::ContentFilterDidBlockLoadForFrame(unblockHandler, m_frame-&gt;frameID()));
</span><span class="cx"> }
</span><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>