<!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>[194950] 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/194950">194950</a></dd>
<dt>Author</dt> <dd>aestes@apple.com</dd>
<dt>Date</dt> <dd>2016-01-12 18:07:11 -0800 (Tue, 12 Jan 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Content Filtering] Lazily load platform frameworks
https://bugs.webkit.org/show_bug.cgi?id=152881
rdar://problem/23270886

Reviewed by Brady Eidson.

Source/WebCore:

On Cocoa platforms, ContentFilter soft-links two frameworks that perform the underlying filtering operations.
There is a one-time cost associated with the soft-linking, and the current design requires all clients to pay
this cost whether or not they ever load a resource that is subject to filtering.

Addressed this by deferring the loading of frameworks until it is known that a resource will require filtering.
It is rather simple to defer the soft-linking at the PlatformContentFilter level, but doing this alone would
mean that every CachedRawResourceClient callback would be routed through ContentFilter, even in the very common
case where both platform content filters are disabled. This is because checking if a platform content filter is
enabled involves loading its framework, so creating a ContentFilter (which DocumentLoader will add as the
CachedRawResource client in place of itself) cannot be avoided by checking that all its platform content filters
are disabled.

Resolved this by inverting the relationship between ContentFilter and DocumentLoader. Instead of ContentFilter
being the CachedRawResource's client and forwarding callbacks to DocumentLoader when one or more platform
filters are enabled, DocumentLoader is now always the client and it forwards callbacks to ContentFilter.
ContentFilter then returns a boolean value indicating whether or not DocumentLoader should proceed with each
callback.

New API test: ContentFiltering.LazilyLoadPlatformFrameworks

* loader/ContentFilter.cpp:
(WebCore::ContentFilter::create): Renamed from createIfEnabled(). Since the enabled check causes frameworks to
be loaded, the check is skipped here and all types are always created.
(WebCore::ContentFilter::continueAfterWillSendRequest): Renamed from willSendRequest(). Renamed requestCopy to
originalRequest, and only created it for logging purposes. Since the copy was only used for logging purposes,
request is now modified directly. Returned false if request is null.
(WebCore::ContentFilter::continueAfterResponseReceived): Renamed from responseReceived(). Stopped asserting that
resource is non-null, since it will be null in the case of substitute data loads. Stopped asserting that m_state
is not Initialized, since that state was removed and the function can now be called in all states. Only logged
if m_state is Filtering. Returned false if m_state is Blocked.
(WebCore::ContentFilter::continueAfterDataReceived): Renamed from dataReceived(). Stopped asserting that
resource is non-null and that m_state is Initialized, and moved the logging, for the same reasons as above.
Returned false if m_state is Filtering or Blocked.
(WebCore::ContentFilter::continueAfterNotifyFinished): Renamed from notifyFinished(). Stopped asserting that
resource is non-null and that m_state is not Initialized, and moved the logging, for the same reasons as above.
If m_state is not Blocked at this point, set m_state to Allowed in order for deliverResourceData() to not get
caught in continueAfterDataReceived(). Returned false if m_state is Blocked or Stopped after delivering data.
(WebCore::ContentFilter::createIfEnabled): Renamed to create().
(WebCore::ContentFilter::~ContentFilter): Stopped removing ourself as m_mainResource's client.
(WebCore::ContentFilter::willSendRequest): Renamed to continueAfterWillSendRequest().
(WebCore::ContentFilter::startFilteringMainResource): Stopped adding ourself as m_mainResource's client. Stopped
asserting that m_state is not Initialized and instead returned early if m_state is not Stopped.
(WebCore::ContentFilter::stopFilteringMainResource): Stopped removing ourself as m_mainResource's client.
(WebCore::ContentFilter::responseReceived): Renamed to continueAfterResponseReceived().
(WebCore::ContentFilter::dataReceived): Renamed to continueAfterDataReceived().
(WebCore::ContentFilter::redirectReceived): Removed. DocumentLoader now calls continueAfterWillSendRequest()
directly on redirects.
(WebCore::ContentFilter::notifyFinished): Renamed to continueAfterNotifyFinished().
(WebCore::ContentFilter::didDecide): Instead of calling DocumentLoader::contentFilterDidDecide(), called
DocumentLoader::contentFilterDidBlock() when m_state is Blocked.
(WebCore::ContentFilter::deliverResourceData): Asserted that m_state is Allowed.
* loader/ContentFilter.h: Stopped inheriting from CachedRawResourceClient. Redeclared the
CachedRawResourceClient virtual functions as the continue* functions mentioned above. Made State enum private
and removed Initialized. Initialized m_state to Stopped and removed its getter.
(WebCore::ContentFilter::type): Returned a ContentFilter::Type that does not include an enabled function.
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::notifyFinished): Returned early if ContentFilter::continueAfterNotifyFinished()
returned false.
(WebCore::DocumentLoader::willSendRequest): Called ContentFilter::continueAfterWillSendRequest() even for
redirects, since ContentFilter is no longer a CachedRawResourceClient and so will no longer receive
redirectReceived(). Returned early if continueAfterWillSendRequest() returns false.
(WebCore::DocumentLoader::responseReceived): Returned early if ContentFilter::continueAfterResponseReceived()
returned false.
(WebCore::DocumentLoader::dataReceived): Ditto for ContentFilter::continueAfterDataReceived().
(WebCore::DocumentLoader::startLoadingMainResource): Called ContentFilter::create(), not createIfEnabled().
(WebCore::DocumentLoader::becomeMainResourceClient): Called ContentFilter::startFilteringMainResource() even if
m_state is not Initialized. Added ourself as a client of m_mainResource unconditionally.
(WebCore::DocumentLoader::contentFilterDidBlock): Renamed from contentFilterDidDecide. Removed assertions and
the early return when m_state is Allowed, since the state is guaranteed to be Blocked.
(WebCore::DocumentLoader::contentFilterDidDecide): Renamed to contentFilterDidBlock.
* platform/cocoa/NetworkExtensionContentFilter.h: Moved definition of HAVE_NETWORK_EXTENSION to Platform.h so
that this file doesn't need to become a Private header. Made enabled() private, and declared initialize().
* platform/cocoa/NetworkExtensionContentFilter.mm:
(WebCore::NetworkExtensionContentFilter::initialize): Added a function to lazily initialize the object.
(WebCore::NetworkExtensionContentFilter::willSendRequest): For the modern NEFilterSource, checked if it is
enabled only after checking if the request is HTTP(S). If both checks pass, then called initialize().
(WebCore::NetworkExtensionContentFilter::responseReceived): Ditto for the legacy NEFilterSource.
* platform/cocoa/ParentalControlsContentFilter.h: Made enabled() private.
* platform/cocoa/ParentalControlsContentFilter.mm:
(WebCore::ParentalControlsContentFilter::responseReceived): Checked if WebFilterEvaluator is enabled only after
checking if the response is from a protocol that can be handled.
* testing/MockContentFilter.cpp:
(WebCore::MockContentFilter::willSendRequest): Immediately set m_status to Status::Allowed if !enabled().
* testing/MockContentFilter.h: Made enabled() private.

Source/WTF:

* wtf/Platform.h: Moved definition of HAVE_NETWORK_EXTENSION to here from WebCore/platform/cocoa/NetworkExtensionContentFilter.h.

Tools:

Added an API test that verifies that the Parental Controls and Network Extension frameworks are loaded at the
expected times. The test verifies that they are not loaded after creating a WKWebView, loading an HTML string,
loading NSData, loading a file, or loading from a custom protocol. It verifies that Network Extension on Mac/iOS
and Parental Controls on iOS are loaded after an HTTP request. It finally verifies that Parental Controls on Mac
is loaded after an HTTPS request.

To accomplish this, TestProtocol was generalized to allow tests to specify the scheme they wish to use.
Other tests that used TestProtocol were updated to account for this change. TestProtocol was removed from
WebKit2.PreventImageLoadWithAutoResizingTest, which didn't actually need to use it. ContentFiltering tests were
also re-enabled on iOS after mistakenly being disabled by <a href="http://trac.webkit.org/projects/webkit/changeset/188892">r188892</a>.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h: Added.
* TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html: Added.
* TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm:
(TEST):
(downloadTest):
(-[LazilyLoadPlatformFrameworksController init]):
(-[LazilyLoadPlatformFrameworksController webView]):
(-[LazilyLoadPlatformFrameworksController expectParentalControlsLoaded:networkExtensionLoaded:]):
(-[LazilyLoadPlatformFrameworksController webView:didFinishNavigation:]):
* TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm:
(-[ContentFilteringPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
(-[ContentFilteringPlugIn observeValueForKeyPath:ofObject:change:context:]):
(-[ContentFilteringPlugIn checkIfPlatformFrameworksAreLoaded:]):
* TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm:
(TestWebKitAPI::TEST): Deleted.
* TestWebKitAPI/cocoa/TestProtocol.h:
* TestWebKitAPI/cocoa/TestProtocol.mm:
(+[TestProtocol registerWithScheme:]):
(+[TestProtocol unregister]):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfPlatformh">trunk/Source/WTF/wtf/Platform.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</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="#trunkSourceWebCoreloaderDocumentLoaderh">trunk/Source/WebCore/loader/DocumentLoader.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaNetworkExtensionContentFilterh">trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaNetworkExtensionContentFiltermm">trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaParentalControlsContentFilterh">trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h</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="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsCustomProtocolsSyncXHRTestmm">trunk/Tools/TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringmm">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringPlugInmm">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2ObjCCustomProtocolsTestmm">trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2ObjCPreventImageLoadWithAutoResizingmm">trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPIcocoaTestProtocolh">trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h</a></li>
<li><a href="#trunkToolsTestWebKitAPIcocoaTestProtocolmm">trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringh">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WTF/ChangeLog        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-01-08  Andy Estes  &lt;aestes@apple.com&gt;
+
+        [Content Filtering] Lazily load platform frameworks
+        https://bugs.webkit.org/show_bug.cgi?id=152881
+        rdar://problem/23270886
+
+        Reviewed by Brady Eidson.
+
+        * wtf/Platform.h: Moved definition of HAVE_NETWORK_EXTENSION to here from WebCore/platform/cocoa/NetworkExtensionContentFilter.h.
+
</ins><span class="cx"> 2016-01-12  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Add a build flag for custom element
</span></span></pre></div>
<a id="trunkSourceWTFwtfPlatformh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Platform.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Platform.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WTF/wtf/Platform.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -531,6 +531,7 @@
</span><span class="cx"> #define HAVE_SEC_KEYCHAIN 1
</span><span class="cx"> 
</span><span class="cx"> #if CPU(X86_64)
</span><ins>+#define HAVE_NETWORK_EXTENSION 1
</ins><span class="cx"> #define USE_PLUGIN_HOST_PROCESS 1
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -544,6 +545,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> 
</span><ins>+#define HAVE_NETWORK_EXTENSION 1
</ins><span class="cx"> #define HAVE_READLINE 1
</span><span class="cx"> #if USE(APPLE_INTERNAL_SDK)
</span><span class="cx"> #define USE_CFNETWORK 1
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/ChangeLog        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -1,3 +1,96 @@
</span><ins>+2016-01-08  Andy Estes  &lt;aestes@apple.com&gt;
+
+        [Content Filtering] Lazily load platform frameworks
+        https://bugs.webkit.org/show_bug.cgi?id=152881
+        rdar://problem/23270886
+
+        Reviewed by Brady Eidson.
+
+        On Cocoa platforms, ContentFilter soft-links two frameworks that perform the underlying filtering operations.
+        There is a one-time cost associated with the soft-linking, and the current design requires all clients to pay
+        this cost whether or not they ever load a resource that is subject to filtering.
+
+        Addressed this by deferring the loading of frameworks until it is known that a resource will require filtering.
+        It is rather simple to defer the soft-linking at the PlatformContentFilter level, but doing this alone would
+        mean that every CachedRawResourceClient callback would be routed through ContentFilter, even in the very common
+        case where both platform content filters are disabled. This is because checking if a platform content filter is
+        enabled involves loading its framework, so creating a ContentFilter (which DocumentLoader will add as the
+        CachedRawResource client in place of itself) cannot be avoided by checking that all its platform content filters
+        are disabled.
+
+        Resolved this by inverting the relationship between ContentFilter and DocumentLoader. Instead of ContentFilter
+        being the CachedRawResource's client and forwarding callbacks to DocumentLoader when one or more platform
+        filters are enabled, DocumentLoader is now always the client and it forwards callbacks to ContentFilter.
+        ContentFilter then returns a boolean value indicating whether or not DocumentLoader should proceed with each
+        callback.
+
+        New API test: ContentFiltering.LazilyLoadPlatformFrameworks
+
+        * loader/ContentFilter.cpp:
+        (WebCore::ContentFilter::create): Renamed from createIfEnabled(). Since the enabled check causes frameworks to
+        be loaded, the check is skipped here and all types are always created.
+        (WebCore::ContentFilter::continueAfterWillSendRequest): Renamed from willSendRequest(). Renamed requestCopy to
+        originalRequest, and only created it for logging purposes. Since the copy was only used for logging purposes,
+        request is now modified directly. Returned false if request is null.
+        (WebCore::ContentFilter::continueAfterResponseReceived): Renamed from responseReceived(). Stopped asserting that
+        resource is non-null, since it will be null in the case of substitute data loads. Stopped asserting that m_state
+        is not Initialized, since that state was removed and the function can now be called in all states. Only logged
+        if m_state is Filtering. Returned false if m_state is Blocked.
+        (WebCore::ContentFilter::continueAfterDataReceived): Renamed from dataReceived(). Stopped asserting that
+        resource is non-null and that m_state is Initialized, and moved the logging, for the same reasons as above.
+        Returned false if m_state is Filtering or Blocked.
+        (WebCore::ContentFilter::continueAfterNotifyFinished): Renamed from notifyFinished(). Stopped asserting that
+        resource is non-null and that m_state is not Initialized, and moved the logging, for the same reasons as above.
+        If m_state is not Blocked at this point, set m_state to Allowed in order for deliverResourceData() to not get
+        caught in continueAfterDataReceived(). Returned false if m_state is Blocked or Stopped after delivering data.
+        (WebCore::ContentFilter::createIfEnabled): Renamed to create().
+        (WebCore::ContentFilter::~ContentFilter): Stopped removing ourself as m_mainResource's client.
+        (WebCore::ContentFilter::willSendRequest): Renamed to continueAfterWillSendRequest().
+        (WebCore::ContentFilter::startFilteringMainResource): Stopped adding ourself as m_mainResource's client. Stopped
+        asserting that m_state is not Initialized and instead returned early if m_state is not Stopped.
+        (WebCore::ContentFilter::stopFilteringMainResource): Stopped removing ourself as m_mainResource's client.
+        (WebCore::ContentFilter::responseReceived): Renamed to continueAfterResponseReceived().
+        (WebCore::ContentFilter::dataReceived): Renamed to continueAfterDataReceived().
+        (WebCore::ContentFilter::redirectReceived): Removed. DocumentLoader now calls continueAfterWillSendRequest()
+        directly on redirects.
+        (WebCore::ContentFilter::notifyFinished): Renamed to continueAfterNotifyFinished().
+        (WebCore::ContentFilter::didDecide): Instead of calling DocumentLoader::contentFilterDidDecide(), called
+        DocumentLoader::contentFilterDidBlock() when m_state is Blocked.
+        (WebCore::ContentFilter::deliverResourceData): Asserted that m_state is Allowed.
+        * loader/ContentFilter.h: Stopped inheriting from CachedRawResourceClient. Redeclared the
+        CachedRawResourceClient virtual functions as the continue* functions mentioned above. Made State enum private
+        and removed Initialized. Initialized m_state to Stopped and removed its getter.
+        (WebCore::ContentFilter::type): Returned a ContentFilter::Type that does not include an enabled function.
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::notifyFinished): Returned early if ContentFilter::continueAfterNotifyFinished()
+        returned false.
+        (WebCore::DocumentLoader::willSendRequest): Called ContentFilter::continueAfterWillSendRequest() even for
+        redirects, since ContentFilter is no longer a CachedRawResourceClient and so will no longer receive
+        redirectReceived(). Returned early if continueAfterWillSendRequest() returns false.
+        (WebCore::DocumentLoader::responseReceived): Returned early if ContentFilter::continueAfterResponseReceived()
+        returned false.
+        (WebCore::DocumentLoader::dataReceived): Ditto for ContentFilter::continueAfterDataReceived().
+        (WebCore::DocumentLoader::startLoadingMainResource): Called ContentFilter::create(), not createIfEnabled().
+        (WebCore::DocumentLoader::becomeMainResourceClient): Called ContentFilter::startFilteringMainResource() even if
+        m_state is not Initialized. Added ourself as a client of m_mainResource unconditionally.
+        (WebCore::DocumentLoader::contentFilterDidBlock): Renamed from contentFilterDidDecide. Removed assertions and
+        the early return when m_state is Allowed, since the state is guaranteed to be Blocked.
+        (WebCore::DocumentLoader::contentFilterDidDecide): Renamed to contentFilterDidBlock.
+        * platform/cocoa/NetworkExtensionContentFilter.h: Moved definition of HAVE_NETWORK_EXTENSION to Platform.h so
+        that this file doesn't need to become a Private header. Made enabled() private, and declared initialize().
+        * platform/cocoa/NetworkExtensionContentFilter.mm:
+        (WebCore::NetworkExtensionContentFilter::initialize): Added a function to lazily initialize the object.
+        (WebCore::NetworkExtensionContentFilter::willSendRequest): For the modern NEFilterSource, checked if it is
+        enabled only after checking if the request is HTTP(S). If both checks pass, then called initialize().
+        (WebCore::NetworkExtensionContentFilter::responseReceived): Ditto for the legacy NEFilterSource.
+        * platform/cocoa/ParentalControlsContentFilter.h: Made enabled() private.
+        * platform/cocoa/ParentalControlsContentFilter.mm:
+        (WebCore::ParentalControlsContentFilter::responseReceived): Checked if WebFilterEvaluator is enabled only after
+        checking if the response is from a protocol that can be handled.
+        * testing/MockContentFilter.cpp:
+        (WebCore::MockContentFilter::willSendRequest): Immediately set m_status to Status::Allowed if !enabled().
+        * testing/MockContentFilter.h: Made enabled() private.
+
</ins><span class="cx"> 2016-01-12  Commit Queue  &lt;commit-queue@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r194926 and r194928.
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderContentFiltercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ContentFilter.cpp (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ContentFilter.cpp        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/loader/ContentFilter.cpp        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -59,13 +59,10 @@
</span><span class="cx">     return types;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-std::unique_ptr&lt;ContentFilter&gt; ContentFilter::createIfEnabled(DocumentLoader&amp; documentLoader)
</del><ins>+std::unique_ptr&lt;ContentFilter&gt; ContentFilter::create(DocumentLoader&amp; documentLoader)
</ins><span class="cx"> {
</span><span class="cx">     Container filters;
</span><span class="cx">     for (auto&amp; type : types()) {
</span><del>-        if (!type.enabled())
-            continue;
-
</del><span class="cx">         auto filter = type.create();
</span><span class="cx">         ASSERT(filter);
</span><span class="cx">         filters.append(WTFMove(filter));
</span><span class="lines">@@ -88,48 +85,41 @@
</span><span class="cx"> ContentFilter::~ContentFilter()
</span><span class="cx"> {
</span><span class="cx">     LOG(ContentFiltering, &quot;Destroying ContentFilter.\n&quot;);
</span><del>-    if (!m_mainResource)
-        return;
-    ASSERT(m_mainResource-&gt;hasClient(this));
-    m_mainResource-&gt;removeClient(this);
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ContentFilter::willSendRequest(ResourceRequest&amp; request, const ResourceResponse&amp; redirectResponse)
</del><ins>+bool ContentFilter::continueAfterWillSendRequest(ResourceRequest&amp; request, const ResourceResponse&amp; redirectResponse)
</ins><span class="cx"> {
</span><span class="cx">     LOG(ContentFiltering, &quot;ContentFilter received request for &lt;%s&gt; with redirect response from &lt;%s&gt;.\n&quot;, request.url().string().ascii().data(), redirectResponse.url().string().ascii().data());
</span><del>-    ResourceRequest requestCopy { request };
-    ASSERT(m_state == State::Initialized || m_state == State::Filtering);
-    forEachContentFilterUntilBlocked([&amp;requestCopy, &amp;redirectResponse](PlatformContentFilter&amp; contentFilter) {
-        contentFilter.willSendRequest(requestCopy, redirectResponse);
-        if (contentFilter.didBlockData())
-            requestCopy = ResourceRequest();
</del><ins>+#if !LOG_DISABLED
+    ResourceRequest originalRequest { request };
+#endif
+    ASSERT(m_state == State::Stopped || m_state == State::Filtering);
+    forEachContentFilterUntilBlocked([&amp;request, &amp;redirectResponse](PlatformContentFilter&amp; contentFilter) {
+        contentFilter.willSendRequest(request, redirectResponse);
</ins><span class="cx">     });
</span><ins>+    if (m_state == State::Blocked)
+        request = ResourceRequest();
</ins><span class="cx"> #if !LOG_DISABLED
</span><del>-    if (request != requestCopy)
-        LOG(ContentFiltering, &quot;ContentFilter changed request url to &lt;%s&gt;.\n&quot;, requestCopy.url().string().ascii().data());
</del><ins>+    if (request != originalRequest)
+        LOG(ContentFiltering, &quot;ContentFilter changed request url to &lt;%s&gt;.\n&quot;, originalRequest.url().string().ascii().data());
</ins><span class="cx"> #endif
</span><del>-    request = requestCopy;
</del><ins>+    return !request.isNull();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ContentFilter::startFilteringMainResource(CachedRawResource&amp; resource)
</span><span class="cx"> {
</span><ins>+    if (m_state != State::Stopped)
+        return;
+
</ins><span class="cx">     LOG(ContentFiltering, &quot;ContentFilter will start filtering main resource at &lt;%s&gt;.\n&quot;, resource.url().string().ascii().data());
</span><del>-    ASSERT(m_state == State::Initialized);
</del><span class="cx">     m_state = State::Filtering;
</span><span class="cx">     ASSERT(!m_mainResource);
</span><span class="cx">     m_mainResource = &amp;resource;
</span><del>-    ASSERT(!m_mainResource-&gt;hasClient(this));
-    m_mainResource-&gt;addClient(this);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ContentFilter::stopFilteringMainResource()
</span><span class="cx"> {
</span><span class="cx">     m_state = State::Stopped;
</span><del>-    if (!m_mainResource)
-        return;
-
-    ASSERT(m_mainResource-&gt;hasClient(this));
-    m_mainResource-&gt;removeClient(this);
</del><span class="cx">     m_mainResource = nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -157,83 +147,61 @@
</span><span class="cx">     return m_blockingContentFilter-&gt;unblockRequestDeniedScript();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse&amp; response)
</del><ins>+bool ContentFilter::continueAfterResponseReceived(CachedResource* resource, const ResourceResponse&amp; response)
</ins><span class="cx"> {
</span><del>-    ASSERT(resource);
-    ASSERT(resource == m_mainResource);
-    ASSERT(m_state != State::Initialized);
-    LOG(ContentFiltering, &quot;ContentFilter received response from &lt;%s&gt;.\n&quot;, response.url().string().ascii().data());
</del><ins>+    ASSERT_UNUSED(resource, resource == m_mainResource);
</ins><span class="cx"> 
</span><span class="cx">     if (m_state == State::Filtering) {
</span><ins>+        LOG(ContentFiltering, &quot;ContentFilter received response from &lt;%s&gt;.\n&quot;, response.url().string().ascii().data());
</ins><span class="cx">         forEachContentFilterUntilBlocked([&amp;response](PlatformContentFilter&amp; contentFilter) {
</span><span class="cx">             contentFilter.responseReceived(response);
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_state != State::Blocked)
-        m_documentLoader.responseReceived(resource, response);
</del><ins>+    return m_state != State::Blocked;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length)
</del><ins>+bool ContentFilter::continueAfterDataReceived(CachedResource* resource, const char* data, int length)
</ins><span class="cx"> {
</span><del>-    ASSERT(resource);
</del><span class="cx">     ASSERT(resource == m_mainResource);
</span><del>-    ASSERT(m_state != State::Initialized);
-    LOG(ContentFiltering, &quot;ContentFilter received %d bytes of data from &lt;%s&gt;.\n&quot;, length, resource-&gt;url().string().ascii().data());
</del><span class="cx"> 
</span><span class="cx">     if (m_state == State::Filtering) {
</span><ins>+        LOG(ContentFiltering, &quot;ContentFilter received %d bytes of data from &lt;%s&gt;.\n&quot;, length, resource-&gt;url().string().ascii().data());
</ins><span class="cx">         forEachContentFilterUntilBlocked([data, length](PlatformContentFilter&amp; contentFilter) {
</span><span class="cx">             contentFilter.addData(data, length);
</span><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         if (m_state == State::Allowed)
</span><span class="cx">             deliverResourceData(*resource);
</span><del>-        return;
</del><ins>+        return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_state == State::Allowed)
-        m_documentLoader.dataReceived(resource, data, length);
</del><ins>+    return m_state != State::Blocked;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ContentFilter::redirectReceived(CachedResource* resource, ResourceRequest&amp; request, const ResourceResponse&amp; redirectResponse)
</del><ins>+bool ContentFilter::continueAfterNotifyFinished(CachedResource* resource)
</ins><span class="cx"> {
</span><del>-    ASSERT(resource);
</del><span class="cx">     ASSERT(resource == m_mainResource);
</span><del>-    ASSERT(m_state != State::Initialized);
</del><span class="cx"> 
</span><del>-    if (m_state == State::Filtering)
-        willSendRequest(request, redirectResponse);
</del><ins>+    if (resource-&gt;errorOccurred())
+        return true;
</ins><span class="cx"> 
</span><del>-    if (m_state != State::Blocked)
-        m_documentLoader.redirectReceived(resource, request, redirectResponse);
-}
-
-void ContentFilter::notifyFinished(CachedResource* resource)
-{
-    ASSERT(resource);
-    ASSERT(resource == m_mainResource);
-    ASSERT(m_state != State::Initialized);
-    LOG(ContentFiltering, &quot;ContentFilter will finish filtering main resource at &lt;%s&gt;.\n&quot;, resource-&gt;url().string().ascii().data());
-
-    if (resource-&gt;errorOccurred()) {
-        m_documentLoader.notifyFinished(resource);
-        return;
-    }
-
</del><span class="cx">     if (m_state == State::Filtering) {
</span><ins>+        LOG(ContentFiltering, &quot;ContentFilter will finish filtering main resource at &lt;%s&gt;.\n&quot;, resource-&gt;url().string().ascii().data());
</ins><span class="cx">         forEachContentFilterUntilBlocked([](PlatformContentFilter&amp; contentFilter) {
</span><span class="cx">             contentFilter.finishedAddingData();
</span><span class="cx">         });
</span><span class="cx"> 
</span><del>-        if (m_state != State::Blocked)
</del><ins>+        if (m_state != State::Blocked) {
+            m_state = State::Allowed;
</ins><span class="cx">             deliverResourceData(*resource);
</span><del>-        
</del><ins>+        }
+
</ins><span class="cx">         if (m_state == State::Stopped)
</span><del>-            return;
</del><ins>+            return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_state != State::Blocked)
-        m_documentLoader.notifyFinished(resource);
</del><ins>+    return m_state != State::Blocked;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ContentFilter::forEachContentFilterUntilBlocked(std::function&lt;void(PlatformContentFilter&amp;)&gt; function)
</span><span class="lines">@@ -267,11 +235,13 @@
</span><span class="cx">     ASSERT(state == State::Allowed || state == State::Blocked);
</span><span class="cx">     LOG(ContentFiltering, &quot;ContentFilter decided load should be %s for main resource at &lt;%s&gt;.\n&quot;, state == State::Allowed ? &quot;allowed&quot; : &quot;blocked&quot;, m_mainResource ? m_mainResource-&gt;url().string().ascii().data() : &quot;&quot;);
</span><span class="cx">     m_state = state;
</span><del>-    m_documentLoader.contentFilterDidDecide();
</del><ins>+    if (m_state == State::Blocked)
+        m_documentLoader.contentFilterDidBlock();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ContentFilter::deliverResourceData(CachedResource&amp; resource)
</span><span class="cx"> {
</span><ins>+    ASSERT(m_state == State::Allowed);
</ins><span class="cx">     ASSERT(resource.dataBufferingPolicy() == BufferData);
</span><span class="cx">     if (auto* resourceBuffer = resource.resourceBuffer())
</span><span class="cx">         m_documentLoader.dataReceived(&amp;resource, resourceBuffer-&gt;data(), resourceBuffer-&gt;size());
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ContentFilter.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ContentFilter.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/loader/ContentFilter.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -28,7 +28,6 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><span class="cx"> 
</span><del>-#include &quot;CachedRawResourceClient.h&quot;
</del><span class="cx"> #include &quot;CachedResourceHandle.h&quot;
</span><span class="cx"> #include &lt;functional&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="lines">@@ -39,39 +38,43 @@
</span><span class="cx"> class ContentFilterUnblockHandler;
</span><span class="cx"> class DocumentLoader;
</span><span class="cx"> class PlatformContentFilter;
</span><ins>+class ResourceRequest;
+class ResourceResponse;
</ins><span class="cx"> class SharedBuffer;
</span><span class="cx"> 
</span><del>-class ContentFilter final : private CachedRawResourceClient {
</del><ins>+class ContentFilter {
</ins><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(ContentFilter);
</span><span class="cx"> 
</span><span class="cx"> public:
</span><span class="cx">     template &lt;typename T&gt; static void addType() { types().append(type&lt;T&gt;()); }
</span><span class="cx"> 
</span><del>-    static std::unique_ptr&lt;ContentFilter&gt; createIfEnabled(DocumentLoader&amp;);
-    ~ContentFilter() override;
</del><ins>+    static std::unique_ptr&lt;ContentFilter&gt; create(DocumentLoader&amp;);
+    ~ContentFilter();
</ins><span class="cx"> 
</span><span class="cx">     static const char* urlScheme() { return &quot;x-apple-content-filter&quot;; }
</span><span class="cx"> 
</span><del>-    void willSendRequest(ResourceRequest&amp;, const ResourceResponse&amp;);
</del><span class="cx">     void startFilteringMainResource(CachedRawResource&amp;);
</span><span class="cx">     void stopFilteringMainResource();
</span><span class="cx"> 
</span><ins>+    bool continueAfterWillSendRequest(ResourceRequest&amp;, const ResourceResponse&amp;);
+    bool continueAfterResponseReceived(CachedResource*, const ResourceResponse&amp;);
+    bool continueAfterDataReceived(CachedResource*, const char* data, int length);
+    bool continueAfterNotifyFinished(CachedResource*);
+
+    ContentFilterUnblockHandler unblockHandler() const;
+    Ref&lt;SharedBuffer&gt; replacementData() const;
+    String unblockRequestDeniedScript() const;
+
+private:
</ins><span class="cx">     enum class State {
</span><del>-        Initialized,
</del><ins>+        Stopped,
</ins><span class="cx">         Filtering,
</span><span class="cx">         Allowed,
</span><span class="cx">         Blocked,
</span><del>-        Stopped
</del><span class="cx">     };
</span><del>-    State state() const { return m_state; }
-    ContentFilterUnblockHandler unblockHandler() const;
-    Ref&lt;SharedBuffer&gt; replacementData() const;
-    String unblockRequestDeniedScript() const;
</del><span class="cx"> 
</span><del>-private:
</del><span class="cx">     struct Type {
</span><del>-        const std::function&lt;bool()&gt; enabled;
</del><span class="cx">         const std::function&lt;std::unique_ptr&lt;PlatformContentFilter&gt;()&gt; create;
</span><span class="cx">     };
</span><span class="cx">     template &lt;typename T&gt; static Type type();
</span><span class="lines">@@ -81,14 +84,6 @@
</span><span class="cx">     friend std::unique_ptr&lt;ContentFilter&gt; std::make_unique&lt;ContentFilter&gt;(Container&amp;&amp;, DocumentLoader&amp;);
</span><span class="cx">     ContentFilter(Container, DocumentLoader&amp;);
</span><span class="cx"> 
</span><del>-    // CachedRawResourceClient
-    void responseReceived(CachedResource*, const ResourceResponse&amp;) override;
-    void dataReceived(CachedResource*, const char* data, int length) override;
-    void redirectReceived(CachedResource*, ResourceRequest&amp;, const ResourceResponse&amp;) override;
-
-    // CachedResourceClient
-    void notifyFinished(CachedResource*) override;
-
</del><span class="cx">     void forEachContentFilterUntilBlocked(std::function&lt;void(PlatformContentFilter&amp;)&gt;);
</span><span class="cx">     void didDecide(State);
</span><span class="cx">     void deliverResourceData(CachedResource&amp;);
</span><span class="lines">@@ -97,14 +92,14 @@
</span><span class="cx">     DocumentLoader&amp; m_documentLoader;
</span><span class="cx">     CachedResourceHandle&lt;CachedRawResource&gt; m_mainResource;
</span><span class="cx">     PlatformContentFilter* m_blockingContentFilter { nullptr };
</span><del>-    State m_state { State::Initialized };
</del><ins>+    State m_state { State::Stopped };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T&gt;
</span><span class="cx"> ContentFilter::Type ContentFilter::type()
</span><span class="cx"> {
</span><span class="cx">     static_assert(std::is_base_of&lt;PlatformContentFilter, T&gt;::value, &quot;Type must be a PlatformContentFilter.&quot;);
</span><del>-    return { T::enabled, T::create };
</del><ins>+    return { T::create };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderDocumentLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/DocumentLoader.cpp        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -370,6 +370,11 @@
</span><span class="cx"> 
</span><span class="cx"> void DocumentLoader::notifyFinished(CachedResource* resource)
</span><span class="cx"> {
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilter &amp;&amp; !m_contentFilter-&gt;continueAfterNotifyFinished(resource))
+        return;
+#endif
+
</ins><span class="cx">     ASSERT_UNUSED(resource, m_mainResource == resource);
</span><span class="cx">     ASSERT(m_mainResource);
</span><span class="cx">     if (!m_mainResource-&gt;errorOccurred() &amp;&amp; !m_mainResource-&gt;wasCanceled()) {
</span><span class="lines">@@ -540,11 +545,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    if (m_contentFilter &amp;&amp; redirectResponse.isNull()) {
-        m_contentFilter-&gt;willSendRequest(newRequest, redirectResponse);
-        if (newRequest.isNull())
-            return;
-    }
</del><ins>+    if (m_contentFilter &amp;&amp; !m_contentFilter-&gt;continueAfterWillSendRequest(newRequest, redirectResponse))
+        return;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     setRequest(newRequest);
</span><span class="lines">@@ -606,6 +608,11 @@
</span><span class="cx"> 
</span><span class="cx"> void DocumentLoader::responseReceived(CachedResource* resource, const ResourceResponse&amp; response)
</span><span class="cx"> {
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilter &amp;&amp; !m_contentFilter-&gt;continueAfterResponseReceived(resource, response))
+        return;
+#endif
+
</ins><span class="cx">     ASSERT_UNUSED(resource, m_mainResource == resource);
</span><span class="cx">     Ref&lt;DocumentLoader&gt; protect(*this);
</span><span class="cx">     bool willLoadFallback = m_applicationCacheHost-&gt;maybeLoadFallbackForMainResponse(request(), response);
</span><span class="lines">@@ -873,6 +880,11 @@
</span><span class="cx"> 
</span><span class="cx"> void DocumentLoader::dataReceived(CachedResource* resource, const char* data, int length)
</span><span class="cx"> {
</span><ins>+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilter &amp;&amp; !m_contentFilter-&gt;continueAfterDataReceived(resource, data, length))
+        return;
+#endif
+
</ins><span class="cx">     ASSERT(data);
</span><span class="cx">     ASSERT(length);
</span><span class="cx">     ASSERT_UNUSED(resource, resource == m_mainResource);
</span><span class="lines">@@ -1418,7 +1430,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    m_contentFilter = !m_originalSubstituteDataWasValid ? ContentFilter::createIfEnabled(*this) : nullptr;
</del><ins>+    m_contentFilter = !m_substituteData.isValid() ? ContentFilter::create(*this) : nullptr;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     // FIXME: Is there any way the extra fields could have not been added by now?
</span><span class="lines">@@ -1624,11 +1636,8 @@
</span><span class="cx"> void DocumentLoader::becomeMainResourceClient()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><del>-    if (m_contentFilter &amp;&amp; m_contentFilter-&gt;state() == ContentFilter::State::Initialized) {
-        // ContentFilter will synthesize CachedRawResourceClient callbacks.
</del><ins>+    if (m_contentFilter)
</ins><span class="cx">         m_contentFilter-&gt;startFilteringMainResource(*m_mainResource);
</span><del>-        return;
-    }
</del><span class="cx"> #endif
</span><span class="cx">     m_mainResource-&gt;addClient(this);
</span><span class="cx"> }
</span><span class="lines">@@ -1666,13 +1675,9 @@
</span><span class="cx">     frameLoader()-&gt;client().contentFilterDidBlockLoad(WTFMove(unblockHandler));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void DocumentLoader::contentFilterDidDecide()
</del><ins>+void DocumentLoader::contentFilterDidBlock()
</ins><span class="cx"> {
</span><del>-    using State = ContentFilter::State;
</del><span class="cx">     ASSERT(m_contentFilter);
</span><del>-    ASSERT(m_contentFilter-&gt;state() == State::Blocked || m_contentFilter-&gt;state() == State::Allowed);
-    if (m_contentFilter-&gt;state() == State::Allowed)
-        return;
</del><span class="cx"> 
</span><span class="cx">     installContentFilterUnblockHandler(*m_contentFilter);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderDocumentLoaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/DocumentLoader.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/DocumentLoader.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/loader/DocumentLoader.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -349,7 +349,7 @@
</span><span class="cx"> #if ENABLE(CONTENT_FILTERING)
</span><span class="cx">         friend class ContentFilter;
</span><span class="cx">         void installContentFilterUnblockHandler(ContentFilter&amp;);
</span><del>-        void contentFilterDidDecide();
</del><ins>+        void contentFilterDidBlock();
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">         Frame* m_frame;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaNetworkExtensionContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -32,8 +32,6 @@
</span><span class="cx"> #include &lt;wtf/OSObjectPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/RetainPtr.h&gt;
</span><span class="cx"> 
</span><del>-#define HAVE_NETWORK_EXTENSION PLATFORM(IOS) || (PLATFORM(MAC) &amp;&amp; CPU(X86_64))
-
</del><span class="cx"> enum NEFilterSourceStatus : NSInteger;
</span><span class="cx"> 
</span><span class="cx"> OBJC_CLASS NEFilterSource;
</span><span class="lines">@@ -41,11 +39,12 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+class URL;
+
</ins><span class="cx"> class NetworkExtensionContentFilter final : public PlatformContentFilter {
</span><span class="cx">     friend std::unique_ptr&lt;NetworkExtensionContentFilter&gt; std::make_unique&lt;NetworkExtensionContentFilter&gt;();
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    static bool enabled();
</del><span class="cx">     static std::unique_ptr&lt;NetworkExtensionContentFilter&gt; create();
</span><span class="cx"> 
</span><span class="cx">     void willSendRequest(ResourceRequest&amp;, const ResourceResponse&amp;) override;
</span><span class="lines">@@ -58,7 +57,10 @@
</span><span class="cx">     ContentFilterUnblockHandler unblockHandler() const override;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    static bool enabled();
+
</ins><span class="cx">     NetworkExtensionContentFilter();
</span><ins>+    void initialize(const URL* = nullptr);
</ins><span class="cx">     void handleDecision(NEFilterSourceStatus, NSData *replacementData);
</span><span class="cx"> 
</span><span class="cx">     NEFilterSourceStatus m_status;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaNetworkExtensionContentFiltermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -65,24 +65,36 @@
</span><span class="cx"> 
</span><span class="cx"> NetworkExtensionContentFilter::NetworkExtensionContentFilter()
</span><span class="cx">     : m_status { NEFilterSourceStatusNeedsMoreData }
</span><del>-    , m_queue { adoptOSObject(dispatch_queue_create(&quot;com.apple.WebCore.NEFilterSourceQueue&quot;, DISPATCH_QUEUE_SERIAL)) }
-    , m_semaphore { adoptOSObject(dispatch_semaphore_create(0)) }
</del><ins>+{
+}
+
+void NetworkExtensionContentFilter::initialize(const URL* url)
+{
+    ASSERT(!m_queue);
+    ASSERT(!m_semaphore);
+    ASSERT(!m_neFilterSource);
+    m_queue = adoptOSObject(dispatch_queue_create(&quot;com.apple.WebCore.NEFilterSourceQueue&quot;, DISPATCH_QUEUE_SERIAL));
+    m_semaphore = adoptOSObject(dispatch_semaphore_create(0));
</ins><span class="cx"> #if HAVE(MODERN_NE_FILTER_SOURCE)
</span><del>-    , m_neFilterSource { adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:m_queue.get()]) }
</del><ins>+    ASSERT_UNUSED(url, !url);
+    m_neFilterSource = adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:m_queue.get()]);
+#else
+    ASSERT_ARG(url, url);
+    m_neFilterSource = adoptNS([allocNEFilterSourceInstance() initWithURL:*url direction:NEFilterSourceDirectionInbound socketIdentifier:0]);
</ins><span class="cx"> #endif
</span><del>-{
-    ASSERT([getNEFilterSourceClass() filterRequired]);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkExtensionContentFilter::willSendRequest(ResourceRequest&amp; request, const ResourceResponse&amp; redirectResponse)
</span><span class="cx"> {
</span><span class="cx"> #if HAVE(MODERN_NE_FILTER_SOURCE)
</span><span class="cx">     ASSERT(!request.isNull());
</span><del>-    if (!request.url().protocolIsInHTTPFamily()) {
</del><ins>+    if (!request.url().protocolIsInHTTPFamily() || !enabled()) {
</ins><span class="cx">         m_status = NEFilterSourceStatusPass;
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    initialize();
+
</ins><span class="cx">     if (!redirectResponse.isNull()) {
</span><span class="cx">         responseReceived(redirectResponse);
</span><span class="cx">         if (!needsMoreData())
</span><span class="lines">@@ -125,8 +137,12 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if !HAVE(MODERN_NE_FILTER_SOURCE)
</span><del>-    ASSERT(!m_neFilterSource);
-    m_neFilterSource = adoptNS([allocNEFilterSourceInstance() initWithURL:response.url() direction:NEFilterSourceDirectionInbound socketIdentifier:0]);
</del><ins>+    if (!enabled()) {
+        m_status = NEFilterSourceStatusPass;
+        return;
+    }
+
+    initialize(&amp;response.url());
</ins><span class="cx"> #else
</span><span class="cx">     [m_neFilterSource receivedResponse:response.nsURLResponse() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
</span><span class="cx">         handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaParentalControlsContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -39,7 +39,6 @@
</span><span class="cx">     friend std::unique_ptr&lt;ParentalControlsContentFilter&gt; std::make_unique&lt;ParentalControlsContentFilter&gt;();
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    static bool enabled();
</del><span class="cx">     static std::unique_ptr&lt;ParentalControlsContentFilter&gt; create();
</span><span class="cx"> 
</span><span class="cx">     void willSendRequest(ResourceRequest&amp;, const ResourceResponse&amp;) override { }
</span><span class="lines">@@ -52,6 +51,8 @@
</span><span class="cx">     ContentFilterUnblockHandler unblockHandler() const override;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    static bool enabled();
+
</ins><span class="cx">     ParentalControlsContentFilter();
</span><span class="cx">     void updateFilterState();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaParentalControlsContentFiltermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -56,7 +56,6 @@
</span><span class="cx"> ParentalControlsContentFilter::ParentalControlsContentFilter()
</span><span class="cx">     : m_filterState { kWFEStateBuffering }
</span><span class="cx"> {
</span><del>-    ASSERT([getWebFilterEvaluatorClass() isManagedSession]);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static inline bool canHandleResponse(const ResourceResponse&amp; response)
</span><span class="lines">@@ -72,7 +71,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_webFilterEvaluator);
</span><span class="cx"> 
</span><del>-    if (!canHandleResponse(response)) {
</del><ins>+    if (!canHandleResponse(response) || !enabled()) {
</ins><span class="cx">         m_filterState = kWFEStateAllowed;
</span><span class="cx">         return;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFiltercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilter.cpp (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilter.cpp        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/testing/MockContentFilter.cpp        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -70,6 +70,11 @@
</span><span class="cx"> 
</span><span class="cx"> void MockContentFilter::willSendRequest(ResourceRequest&amp; request, const ResourceResponse&amp; redirectResponse)
</span><span class="cx"> {
</span><ins>+    if (!enabled()) {
+        m_status = Status::Allowed;
+        return;
+    }
+
</ins><span class="cx">     if (redirectResponse.isNull())
</span><span class="cx">         maybeDetermineStatus(DecisionPoint::AfterWillSendRequest);
</span><span class="cx">     else
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockContentFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockContentFilter.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockContentFilter.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Source/WebCore/testing/MockContentFilter.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -36,7 +36,6 @@
</span><span class="cx"> 
</span><span class="cx"> public:
</span><span class="cx">     static void ensureInstalled();
</span><del>-    static bool enabled();
</del><span class="cx">     static std::unique_ptr&lt;MockContentFilter&gt; create();
</span><span class="cx"> 
</span><span class="cx">     void willSendRequest(ResourceRequest&amp;, const ResourceResponse&amp;) override;
</span><span class="lines">@@ -56,6 +55,8 @@
</span><span class="cx">         Blocked
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    static bool enabled();
+
</ins><span class="cx">     MockContentFilter() = default;
</span><span class="cx">     void maybeDetermineStatus(MockContentFilterSettings::DecisionPoint);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/ChangeLog        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -1,3 +1,47 @@
</span><ins>+2016-01-08  Andy Estes  &lt;aestes@apple.com&gt;
+
+        [Content Filtering] Lazily load platform frameworks
+        https://bugs.webkit.org/show_bug.cgi?id=152881
+        rdar://problem/23270886
+
+        Reviewed by Brady Eidson.
+
+        Added an API test that verifies that the Parental Controls and Network Extension frameworks are loaded at the
+        expected times. The test verifies that they are not loaded after creating a WKWebView, loading an HTML string,
+        loading NSData, loading a file, or loading from a custom protocol. It verifies that Network Extension on Mac/iOS
+        and Parental Controls on iOS are loaded after an HTTP request. It finally verifies that Parental Controls on Mac
+        is loaded after an HTTPS request.
+
+        To accomplish this, TestProtocol was generalized to allow tests to specify the scheme they wish to use.
+        Other tests that used TestProtocol were updated to account for this change. TestProtocol was removed from
+        WebKit2.PreventImageLoadWithAutoResizingTest, which didn't actually need to use it. ContentFiltering tests were
+        also re-enabled on iOS after mistakenly being disabled by r188892.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h: Added.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html: Added.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm:
+        (TEST):
+        (downloadTest):
+        (-[LazilyLoadPlatformFrameworksController init]):
+        (-[LazilyLoadPlatformFrameworksController webView]):
+        (-[LazilyLoadPlatformFrameworksController expectParentalControlsLoaded:networkExtensionLoaded:]):
+        (-[LazilyLoadPlatformFrameworksController webView:didFinishNavigation:]):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm:
+        (-[ContentFilteringPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
+        (-[ContentFilteringPlugIn observeValueForKeyPath:ofObject:change:context:]):
+        (-[ContentFilteringPlugIn checkIfPlatformFrameworksAreLoaded:]):
+        * TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm:
+        (TestWebKitAPI::TEST): Deleted.
+        * TestWebKitAPI/cocoa/TestProtocol.h:
+        * TestWebKitAPI/cocoa/TestProtocol.mm:
+        (+[TestProtocol registerWithScheme:]):
+        (+[TestProtocol unregister]):
+
</ins><span class="cx"> 2016-01-12  Dewei Zhu  &lt;dewei_zhu@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix the Sunpider converage in slow device.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -278,6 +278,7 @@
</span><span class="cx">                 A14FC5881B8991BF00D107EB /* ContentFiltering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5861B8991B600D107EB /* ContentFiltering.mm */; };
</span><span class="cx">                 A14FC58B1B89927100D107EB /* ContentFilteringPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */; };
</span><span class="cx">                 A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC58E1B8AE36500D107EB /* TestProtocol.mm */; };
</span><ins>+                A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */; };
</ins><span class="cx">                 A1C4FB6E1BACCE50003742D0 /* QuickLook.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1C4FB6C1BACCE50003742D0 /* QuickLook.mm */; };
</span><span class="cx">                 A1C4FB731BACD1CA003742D0 /* pages.pages in Copy Resources */ = {isa = PBXBuildFile; fileRef = A1C4FB721BACD1B7003742D0 /* pages.pages */; };
</span><span class="cx">                 A1DF74321C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */; };
</span><span class="lines">@@ -378,6 +379,7 @@
</span><span class="cx">                         dstPath = TestWebKitAPI.resources;
</span><span class="cx">                         dstSubfolderSpec = 7;
</span><span class="cx">                         files = (
</span><ins>+                                A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */,
</ins><span class="cx">                                 CDC8E4941BC6F10800594FEC /* video-with-audio.html in Copy Resources */,
</span><span class="cx">                                 CDC8E4951BC6F10800594FEC /* video-with-audio.mp4 in Copy Resources */,
</span><span class="cx">                                 CDC8E4961BC6F10800594FEC /* video-without-audio.html in Copy Resources */,
</span><span class="lines">@@ -671,6 +673,8 @@
</span><span class="cx">                 A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentFilteringPlugIn.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A14FC58D1B8AE36500D107EB /* TestProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProtocol.h; path = cocoa/TestProtocol.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A14FC58E1B8AE36500D107EB /* TestProtocol.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestProtocol.mm; path = cocoa/TestProtocol.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ContentFiltering.html; sourceTree = &quot;&lt;group&gt;&quot;; };
+                A18AA8CC1C3FA218009B2B97 /* ContentFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentFiltering.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 A1A4FE5D18DD3DB700B5EA8A /* Download.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Download.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A1C4FB6C1BACCE50003742D0 /* QuickLook.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QuickLook.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A1C4FB721BACD1B7003742D0 /* pages.pages */ = {isa = PBXFileReference; lastKnownFileType = file; name = pages.pages; path = ios/pages.pages; sourceTree = SOURCE_ROOT; };
</span><span class="lines">@@ -928,10 +932,12 @@
</span><span class="cx">                 1ABC3DEC1899BE55004F0626 /* WebKit2 Cocoa */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><ins>+                                A16F66B81C40E9E100BD4D24 /* Resources */,
</ins><span class="cx">                                 7CEFA9641AC0B9E200B910FD /* _WKUserContentExtensionStore.mm */,
</span><span class="cx">                                 2DD355351BD08378005DF4A7 /* AutoLayoutIntegration.mm */,
</span><span class="cx">                                 A13EBBAC1B87436F00097110 /* BundleParameters.mm */,
</span><span class="cx">                                 A13EBBAE1B87436F00097110 /* BundleParametersPlugIn.mm */,
</span><ins>+                                A18AA8CC1C3FA218009B2B97 /* ContentFiltering.h */,
</ins><span class="cx">                                 A14FC5861B8991B600D107EB /* ContentFiltering.mm */,
</span><span class="cx">                                 A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */,
</span><span class="cx">                                 A1A4FE5D18DD3DB700B5EA8A /* Download.mm */,
</span><span class="lines">@@ -1020,6 +1026,14 @@
</span><span class="cx">                         path = cocoa/WebProcessPlugIn;
</span><span class="cx">                         sourceTree = &quot;&lt;group&gt;&quot;;
</span><span class="cx">                 };
</span><ins>+                A16F66B81C40E9E100BD4D24 /* Resources */ = {
+                        isa = PBXGroup;
+                        children = (
+                                A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */,
+                        );
+                        name = Resources;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
</ins><span class="cx">                 A1C4FB6F1BACCEFA003742D0 /* Resources */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsCustomProtocolsSyncXHRTestmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -48,8 +48,7 @@
</span><span class="cx"> 
</span><span class="cx"> TEST(WebKit2CustomProtocolsTest, SyncXHR)
</span><span class="cx"> {
</span><del>-    [NSURLProtocol registerClass:[TestProtocol class]];
-    [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
</del><ins>+    [TestProtocol registerWithScheme:@&quot;http&quot;];
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;WKProcessGroup&gt; processGroup = adoptNS([[WKProcessGroup alloc] init]);
</span><span class="cx">     RetainPtr&lt;WKBrowsingContextGroup&gt; browsingContextGroup = adoptNS([[WKBrowsingContextGroup alloc] initWithIdentifier:@&quot;TestIdentifier&quot;]);
</span><span class="lines">@@ -69,8 +68,7 @@
</span><span class="cx">     WKPageLoadURL(wkView.get().pageRef, Util::createURLForResource(&quot;custom-protocol-sync-xhr&quot;, &quot;html&quot;));
</span><span class="cx"> 
</span><span class="cx">     TestWebKitAPI::Util::run(&amp;testFinished);
</span><del>-    [NSURLProtocol unregisterClass:[TestProtocol class]];
-    [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
</del><ins>+    [TestProtocol unregister];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringhfromrev194935trunkToolsTestWebKitAPIcocoaTestProtocolh"></a>
<div class="copfile"><h4>Copied: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h (from rev 194935, trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h) (0 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+@protocol ContentFilteringProtocol &lt;NSObject&gt;
+- (void)checkIfPlatformFrameworksAreLoaded:(void (^)(BOOL parentalControlsLoaded, BOOL networkExtensionLoaded))completionHandler;
+@end
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringhtml"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html (0 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+PASS
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -25,17 +25,19 @@
</span><span class="cx"> 
</span><span class="cx"> #import &quot;config.h&quot;
</span><span class="cx"> 
</span><del>-#if WK_API_ENABLED &amp;&amp; PLATFORM(MAC)
</del><ins>+#if WK_API_ENABLED
</ins><span class="cx"> 
</span><ins>+#import &quot;ContentFiltering.h&quot;
</ins><span class="cx"> #import &quot;MockContentFilterSettings.h&quot;
</span><span class="cx"> #import &quot;PlatformUtilities.h&quot;
</span><span class="cx"> #import &quot;TestProtocol.h&quot;
</span><span class="cx"> #import &quot;WKWebViewConfigurationExtras.h&quot;
</span><del>-#import &lt;WebKit/WKBrowsingContextController.h&gt;
</del><span class="cx"> #import &lt;WebKit/WKNavigationDelegatePrivate.h&gt;
</span><span class="cx"> #import &lt;WebKit/WKProcessPoolPrivate.h&gt;
</span><span class="cx"> #import &lt;WebKit/WKWebView.h&gt;
</span><span class="cx"> #import &lt;WebKit/_WKDownloadDelegate.h&gt;
</span><ins>+#import &lt;WebKit/_WKRemoteObjectInterface.h&gt;
+#import &lt;WebKit/_WKRemoteObjectRegistry.h&gt;
</ins><span class="cx"> #import &lt;wtf/RetainPtr.h&gt;
</span><span class="cx"> 
</span><span class="cx"> using Decision = WebCore::MockContentFilterSettings::Decision;
</span><span class="lines">@@ -118,8 +120,7 @@
</span><span class="cx"> TEST(ContentFiltering, URLAfterServerRedirect)
</span><span class="cx"> {
</span><span class="cx">     @autoreleasepool {
</span><del>-        [NSURLProtocol registerClass:[TestProtocol class]];
-        [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
</del><ins>+        [TestProtocol registerWithScheme:@&quot;http&quot;];
</ins><span class="cx"> 
</span><span class="cx">         auto configuration = configurationWithContentFilterSettings(Decision::Allow, DecisionPoint::AfterAddData);
</span><span class="cx">         auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
</span><span class="lines">@@ -128,8 +129,7 @@
</span><span class="cx">         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@&quot;http://redirect?pass&quot;]]];
</span><span class="cx">         TestWebKitAPI::Util::run(&amp;isDone);
</span><span class="cx"> 
</span><del>-        [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
-        [NSURLProtocol unregisterClass:[TestProtocol class]];
</del><ins>+        [TestProtocol unregister];
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -172,8 +172,7 @@
</span><span class="cx"> static void downloadTest(Decision decision, DecisionPoint decisionPoint)
</span><span class="cx"> {
</span><span class="cx">     @autoreleasepool {
</span><del>-        [NSURLProtocol registerClass:[TestProtocol class]];
-        [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
</del><ins>+        [TestProtocol registerWithScheme:@&quot;http&quot;];
</ins><span class="cx"> 
</span><span class="cx">         auto configuration = configurationWithContentFilterSettings(decision, decisionPoint);
</span><span class="cx">         auto downloadDelegate = adoptNS([[ContentFilteringDownloadDelegate alloc] init]);
</span><span class="lines">@@ -193,8 +192,7 @@
</span><span class="cx"> 
</span><span class="cx">         EXPECT_EQ(downloadShouldStart, downloadDidStart);
</span><span class="cx"> 
</span><del>-        [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
-        [NSURLProtocol unregisterClass:[TestProtocol class]];
</del><ins>+        [TestProtocol unregister];
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -258,4 +256,107 @@
</span><span class="cx">     downloadTest(Decision::Block, DecisionPoint::Never);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+@interface LazilyLoadPlatformFrameworksController : NSObject &lt;WKNavigationDelegate&gt;
+@property (nonatomic, readonly) WKWebView *webView;
+- (void)expectParentalControlsLoaded:(BOOL)parentalControlsShouldBeLoaded networkExtensionLoaded:(BOOL)networkExtensionShouldBeLoaded;
+@end
+
+@implementation LazilyLoadPlatformFrameworksController {
+    RetainPtr&lt;WKWebView&gt; _webView;
+    RetainPtr&lt;id &lt;ContentFilteringProtocol&gt;&gt; _remoteObjectProxy;
+}
+
+- (instancetype)init
+{
+    if (!(self = [super init]))
+        return nil;
+
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration testwebkitapi_configurationWithTestPlugInClassName:@&quot;ContentFilteringPlugIn&quot;];
+    _webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
+    [_webView setNavigationDelegate:self];
+
+    _WKRemoteObjectInterface *interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ContentFilteringProtocol)];
+    _remoteObjectProxy = [[_webView _remoteObjectRegistry] remoteObjectProxyWithInterface:interface];
+
+    return self;
+}
+
+- (WKWebView *)webView
+{
+    return _webView.get();
+}
+
+- (void)expectParentalControlsLoaded:(BOOL)parentalControlsShouldBeLoaded networkExtensionLoaded:(BOOL)networkExtensionShouldBeLoaded
+{
+    isDone = false;
+    [_remoteObjectProxy checkIfPlatformFrameworksAreLoaded:^(BOOL parentalControlsLoaded, BOOL networkExtensionLoaded) {
+#if HAVE(PARENTAL_CONTROLS)
+        EXPECT_EQ(static_cast&lt;bool&gt;(parentalControlsShouldBeLoaded), static_cast&lt;bool&gt;(parentalControlsLoaded));
+#endif
+#if HAVE(NETWORK_EXTENSION)
+        EXPECT_EQ(static_cast&lt;bool&gt;(networkExtensionShouldBeLoaded), static_cast&lt;bool&gt;(networkExtensionLoaded));
+#endif
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&amp;isDone);
+}
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+    isDone = true;
+}
+
+@end
+
+TEST(ContentFiltering, LazilyLoadPlatformFrameworks)
+{
+    @autoreleasepool {
+        auto controller = adoptNS([[LazilyLoadPlatformFrameworksController alloc] init]);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        [[controller webView] loadHTMLString:@&quot;PASS&quot; baseURL:[NSURL URLWithString:@&quot;about:blank&quot;]];
+        TestWebKitAPI::Util::run(&amp;isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        [[controller webView] loadData:[NSData dataWithBytes:&quot;PASS&quot; length:4] MIMEType:@&quot;text/html&quot; characterEncodingName:@&quot;UTF-8&quot; baseURL:[NSURL URLWithString:@&quot;about:blank&quot;]];
+        TestWebKitAPI::Util::run(&amp;isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@&quot;ContentFiltering&quot; withExtension:@&quot;html&quot; subdirectory:@&quot;TestWebKitAPI.resources&quot;];
+        [[controller webView] loadFileURL:fileURL allowingReadAccessToURL:fileURL];
+        TestWebKitAPI::Util::run(&amp;isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        [TestProtocol registerWithScheme:@&quot;custom&quot;];
+        [[controller webView] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@&quot;custom://test&quot;]]];
+        TestWebKitAPI::Util::run(&amp;isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+        [TestProtocol unregister];
+
+        isDone = false;
+        [TestProtocol registerWithScheme:@&quot;http&quot;];
+        [[controller webView] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@&quot;http://test&quot;]]];
+        TestWebKitAPI::Util::run(&amp;isDone);
+#if PLATFORM(MAC)
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:YES];
+#else
+        [controller expectParentalControlsLoaded:YES networkExtensionLoaded:YES];
+#endif
+        [TestProtocol unregister];
+
+#if PLATFORM(MAC)
+        isDone = false;
+        [TestProtocol registerWithScheme:@&quot;https&quot;];
+        [[controller webView] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@&quot;https://test&quot;]]];
+        TestWebKitAPI::Util::run(&amp;isDone);
+        [controller expectParentalControlsLoaded:YES networkExtensionLoaded:YES];
+        [TestProtocol unregister];
+#endif
+    }
+}
+
</ins><span class="cx"> #endif // WK_API_ENABLED
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaContentFilteringPlugInmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -27,8 +27,13 @@
</span><span class="cx"> 
</span><span class="cx"> #if WK_API_ENABLED
</span><span class="cx"> 
</span><ins>+#import &quot;ContentFiltering.h&quot;
</ins><span class="cx"> #import &quot;MockContentFilterSettings.h&quot;
</span><span class="cx"> #import &lt;WebKit/WKWebProcessPlugIn.h&gt;
</span><ins>+#import &lt;WebKit/WKWebProcessPlugInBrowserContextControllerPrivate.h&gt;
+#import &lt;WebKit/_WKRemoteObjectInterface.h&gt;
+#import &lt;WebKit/_WKRemoteObjectRegistry.h&gt;
+#import &lt;mach-o/dyld.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> using MockContentFilterSettings = WebCore::MockContentFilterSettings;
</span><span class="cx"> using Decision = MockContentFilterSettings::Decision;
</span><span class="lines">@@ -73,7 +78,7 @@
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><del>-@interface ContentFilteringPlugIn : NSObject &lt;WKWebProcessPlugIn&gt;
</del><ins>+@interface ContentFilteringPlugIn : NSObject &lt;ContentFilteringProtocol, WKWebProcessPlugIn&gt;
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation ContentFilteringPlugIn {
</span><span class="lines">@@ -88,6 +93,12 @@
</span><span class="cx">     [plugInController.parameters addObserver:self forKeyPath:NSStringFromClass([MockContentFilterEnabler class]) options:NSKeyValueObservingOptionInitial context:NULL];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController didCreateBrowserContextController:(WKWebProcessPlugInBrowserContextController *)browserContextController
+{
+    _WKRemoteObjectInterface *interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ContentFilteringProtocol)];
+    [[browserContextController _remoteObjectRegistry] registerExportedObject:self interface:interface];
+}
+
</ins><span class="cx"> - (void)dealloc
</span><span class="cx"> {
</span><span class="cx">     [[_plugInController parameters] removeObserver:self forKeyPath:NSStringFromClass([MockContentFilterEnabler class])];
</span><span class="lines">@@ -97,10 +108,24 @@
</span><span class="cx"> - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
</span><span class="cx"> {
</span><span class="cx">     id contentFilterEnabler = [object valueForKeyPath:keyPath];
</span><del>-    ASSERT([contentFilterEnabler isKindOfClass:[MockContentFilterEnabler class]]);
</del><ins>+    ASSERT(!contentFilterEnabler || [contentFilterEnabler isKindOfClass:[MockContentFilterEnabler class]]);
</ins><span class="cx">     _contentFilterEnabler = contentFilterEnabler;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)checkIfPlatformFrameworksAreLoaded:(void (^)(BOOL parentalControlsLoaded, BOOL networkExtensionLoaded))completionHandler
+{
+    bool parentalControlsLoaded = false;
+#if HAVE(PARENTAL_CONTROLS)
+    parentalControlsLoaded = NSVersionOfRunTimeLibrary(&quot;WebContentAnalysis&quot;) != -1;
+#endif
+    
+    bool networkExtensionLoaded = false;
+#if HAVE(NETWORK_EXTENSION)
+    networkExtensionLoaded = NSVersionOfRunTimeLibrary(&quot;NetworkExtension&quot;) != -1;
+#endif
+    completionHandler(parentalControlsLoaded, networkExtensionLoaded);
+}
+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> #endif // WK_API_ENABLED
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2ObjCCustomProtocolsTestmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -70,8 +70,7 @@
</span><span class="cx"> 
</span><span class="cx"> TEST(WebKit2CustomProtocolsTest, MainResource)
</span><span class="cx"> {
</span><del>-    [NSURLProtocol registerClass:[TestProtocol class]];
-    [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
</del><ins>+    [TestProtocol registerWithScheme:@&quot;http&quot;];
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;WKProcessGroup&gt; processGroup = adoptNS([[WKProcessGroup alloc] init]);
</span><span class="cx">     RetainPtr&lt;WKBrowsingContextGroup&gt; browsingContextGroup = adoptNS([[WKBrowsingContextGroup alloc] initWithIdentifier:@&quot;TestIdentifier&quot;]);
</span><span class="lines">@@ -81,8 +80,7 @@
</span><span class="cx">     [[wkView browsingContextController] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@&quot;%@://redirect?test&quot;, [TestProtocol scheme]]]]];
</span><span class="cx"> 
</span><span class="cx">     Util::run(&amp;testFinished);
</span><del>-    [NSURLProtocol unregisterClass:[TestProtocol class]];
-    [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
</del><ins>+    [TestProtocol unregister];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2ObjCPreventImageLoadWithAutoResizingmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -32,7 +32,6 @@
</span><span class="cx"> #import &quot;PlatformUtilities.h&quot;
</span><span class="cx"> #import &quot;PlatformWebView.h&quot;
</span><span class="cx"> #import &quot;TestBrowsingContextLoadDelegate.h&quot;
</span><del>-#import &quot;TestProtocol.h&quot;
</del><span class="cx"> #import &lt;WebKit/WKViewPrivate.h&gt;
</span><span class="cx"> 
</span><span class="cx"> #if WK_API_ENABLED &amp;&amp; PLATFORM(MAC)
</span><span class="lines">@@ -43,9 +42,6 @@
</span><span class="cx"> 
</span><span class="cx"> TEST(WebKit2, PreventImageLoadWithAutoResizingTest)
</span><span class="cx"> {
</span><del>-    [NSURLProtocol registerClass:[TestProtocol class]];
-    [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
-
</del><span class="cx">     WKRetainPtr&lt;WKContextRef&gt; context = adoptWK(Util::createContextForInjectedBundleTest(&quot;DenyWillSendRequestTest&quot;));
</span><span class="cx">     PlatformWebView webView(context.get());
</span><span class="cx"> 
</span><span class="lines">@@ -56,8 +52,6 @@
</span><span class="cx">     [webView.platformView().browsingContextController loadHTMLString:@&quot;&lt;html&gt;&lt;body style='background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAFZJREFUeF59z4EJADEIQ1F36k7u5E7ZKXeUQPACJ3wK7UNokVxVk9kHnQH7bY9hbDyDhNXgjpRLqFlo4M2GgfyJHhjq8V4agfrgPQX3JtJQGbofmCHgA/nAKks+JAjFAAAAAElFTkSuQmCC);'&gt;&lt;/body&gt;&lt;/html&gt;&quot; baseURL:[NSURL URLWithString:@&quot;about:blank&quot;]];
</span><span class="cx"> 
</span><span class="cx">     Util::run(&amp;testFinished);
</span><del>-    [NSURLProtocol unregisterClass:[TestProtocol class]];
-    [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIcocoaTestProtocolh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -28,6 +28,8 @@
</span><span class="cx"> 
</span><span class="cx"> @interface TestProtocol : NSURLProtocol {
</span><span class="cx"> }
</span><ins>++ (void)registerWithScheme:(NSString *)scheme;
++ (void)unregister;
</ins><span class="cx"> + (NSString *)scheme;
</span><span class="cx"> @end
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIcocoaTestProtocolmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.mm (194949 => 194950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.mm        2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.mm        2016-01-13 02:07:11 UTC (rev 194950)
</span><span class="lines">@@ -26,11 +26,10 @@
</span><span class="cx"> #import &quot;config.h&quot;
</span><span class="cx"> #import &quot;TestProtocol.h&quot;
</span><span class="cx"> 
</span><ins>+#import &lt;WebKit/WKBrowsingContextController.h&gt;
</ins><span class="cx"> #import &lt;wtf/RetainPtr.h&gt;
</span><span class="cx"> 
</span><del>-// Even though NSURLProtocol is capable of generating redirect responses for any protocol, WebCore asserts if a redirect is not in the http family.
-// See http://webkit.org/b/147870 for details.
-static NSString *testScheme = @&quot;http&quot;;
</del><ins>+static NSString *testScheme;
</ins><span class="cx"> 
</span><span class="cx"> @implementation TestProtocol
</span><span class="cx"> 
</span><span class="lines">@@ -54,6 +53,25 @@
</span><span class="cx">     return testScheme;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>++ (void)registerWithScheme:(NSString *)scheme
+{
+    testScheme = [scheme retain];
+    [NSURLProtocol registerClass:[self class]];
+#if WK_API_ENABLED
+    [WKBrowsingContextController registerSchemeForCustomProtocol:testScheme];
+#endif
+}
+
++ (void)unregister
+{
+#if WK_API_ENABLED
+    [WKBrowsingContextController unregisterSchemeForCustomProtocol:testScheme];
+#endif
+    [NSURLProtocol unregisterClass:[self class]];
+    [testScheme release];
+    testScheme = nil;
+}
+
</ins><span class="cx"> - (void)startLoading
</span><span class="cx"> {
</span><span class="cx">     NSURL *requestURL = self.request.URL;
</span></span></pre>
</div>
</div>

</body>
</html>