Title: [194950] trunk
Revision
194950
Author
[email protected]
Date
2016-01-12 18:07:11 -0800 (Tue, 12 Jan 2016)

Log Message

[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 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]):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (194949 => 194950)


--- 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)
@@ -1,3 +1,13 @@
+2016-01-08  Andy Estes  <[email protected]>
+
+        [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.
+
 2016-01-12  Ryosuke Niwa  <[email protected]>
 
         Add a build flag for custom element

Modified: trunk/Source/WTF/wtf/Platform.h (194949 => 194950)


--- 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)
@@ -531,6 +531,7 @@
 #define HAVE_SEC_KEYCHAIN 1
 
 #if CPU(X86_64)
+#define HAVE_NETWORK_EXTENSION 1
 #define USE_PLUGIN_HOST_PROCESS 1
 #endif
 
@@ -544,6 +545,7 @@
 
 #if PLATFORM(IOS)
 
+#define HAVE_NETWORK_EXTENSION 1
 #define HAVE_READLINE 1
 #if USE(APPLE_INTERNAL_SDK)
 #define USE_CFNETWORK 1

Modified: trunk/Source/WebCore/ChangeLog (194949 => 194950)


--- 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)
@@ -1,3 +1,96 @@
+2016-01-08  Andy Estes  <[email protected]>
+
+        [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.
+
 2016-01-12  Commit Queue  <[email protected]>
 
         Unreviewed, rolling out r194926 and r194928.

Modified: trunk/Source/WebCore/loader/ContentFilter.cpp (194949 => 194950)


--- 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)
@@ -59,13 +59,10 @@
     return types;
 }
 
-std::unique_ptr<ContentFilter> ContentFilter::createIfEnabled(DocumentLoader& documentLoader)
+std::unique_ptr<ContentFilter> ContentFilter::create(DocumentLoader& documentLoader)
 {
     Container filters;
     for (auto& type : types()) {
-        if (!type.enabled())
-            continue;
-
         auto filter = type.create();
         ASSERT(filter);
         filters.append(WTFMove(filter));
@@ -88,48 +85,41 @@
 ContentFilter::~ContentFilter()
 {
     LOG(ContentFiltering, "Destroying ContentFilter.\n");
-    if (!m_mainResource)
-        return;
-    ASSERT(m_mainResource->hasClient(this));
-    m_mainResource->removeClient(this);
 }
 
-void ContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
+bool ContentFilter::continueAfterWillSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
 {
     LOG(ContentFiltering, "ContentFilter received request for <%s> with redirect response from <%s>.\n", request.url().string().ascii().data(), redirectResponse.url().string().ascii().data());
-    ResourceRequest requestCopy { request };
-    ASSERT(m_state == State::Initialized || m_state == State::Filtering);
-    forEachContentFilterUntilBlocked([&requestCopy, &redirectResponse](PlatformContentFilter& contentFilter) {
-        contentFilter.willSendRequest(requestCopy, redirectResponse);
-        if (contentFilter.didBlockData())
-            requestCopy = ResourceRequest();
+#if !LOG_DISABLED
+    ResourceRequest originalRequest { request };
+#endif
+    ASSERT(m_state == State::Stopped || m_state == State::Filtering);
+    forEachContentFilterUntilBlocked([&request, &redirectResponse](PlatformContentFilter& contentFilter) {
+        contentFilter.willSendRequest(request, redirectResponse);
     });
+    if (m_state == State::Blocked)
+        request = ResourceRequest();
 #if !LOG_DISABLED
-    if (request != requestCopy)
-        LOG(ContentFiltering, "ContentFilter changed request url to <%s>.\n", requestCopy.url().string().ascii().data());
+    if (request != originalRequest)
+        LOG(ContentFiltering, "ContentFilter changed request url to <%s>.\n", originalRequest.url().string().ascii().data());
 #endif
-    request = requestCopy;
+    return !request.isNull();
 }
 
 void ContentFilter::startFilteringMainResource(CachedRawResource& resource)
 {
+    if (m_state != State::Stopped)
+        return;
+
     LOG(ContentFiltering, "ContentFilter will start filtering main resource at <%s>.\n", resource.url().string().ascii().data());
-    ASSERT(m_state == State::Initialized);
     m_state = State::Filtering;
     ASSERT(!m_mainResource);
     m_mainResource = &resource;
-    ASSERT(!m_mainResource->hasClient(this));
-    m_mainResource->addClient(this);
 }
 
 void ContentFilter::stopFilteringMainResource()
 {
     m_state = State::Stopped;
-    if (!m_mainResource)
-        return;
-
-    ASSERT(m_mainResource->hasClient(this));
-    m_mainResource->removeClient(this);
     m_mainResource = nullptr;
 }
 
@@ -157,83 +147,61 @@
     return m_blockingContentFilter->unblockRequestDeniedScript();
 }
 
-void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse& response)
+bool ContentFilter::continueAfterResponseReceived(CachedResource* resource, const ResourceResponse& response)
 {
-    ASSERT(resource);
-    ASSERT(resource == m_mainResource);
-    ASSERT(m_state != State::Initialized);
-    LOG(ContentFiltering, "ContentFilter received response from <%s>.\n", response.url().string().ascii().data());
+    ASSERT_UNUSED(resource, resource == m_mainResource);
 
     if (m_state == State::Filtering) {
+        LOG(ContentFiltering, "ContentFilter received response from <%s>.\n", response.url().string().ascii().data());
         forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) {
             contentFilter.responseReceived(response);
         });
     }
 
-    if (m_state != State::Blocked)
-        m_documentLoader.responseReceived(resource, response);
+    return m_state != State::Blocked;
 }
 
-void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length)
+bool ContentFilter::continueAfterDataReceived(CachedResource* resource, const char* data, int length)
 {
-    ASSERT(resource);
     ASSERT(resource == m_mainResource);
-    ASSERT(m_state != State::Initialized);
-    LOG(ContentFiltering, "ContentFilter received %d bytes of data from <%s>.\n", length, resource->url().string().ascii().data());
 
     if (m_state == State::Filtering) {
+        LOG(ContentFiltering, "ContentFilter received %d bytes of data from <%s>.\n", length, resource->url().string().ascii().data());
         forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) {
             contentFilter.addData(data, length);
         });
 
         if (m_state == State::Allowed)
             deliverResourceData(*resource);
-        return;
+        return false;
     }
 
-    if (m_state == State::Allowed)
-        m_documentLoader.dataReceived(resource, data, length);
+    return m_state != State::Blocked;
 }
 
-void ContentFilter::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
+bool ContentFilter::continueAfterNotifyFinished(CachedResource* resource)
 {
-    ASSERT(resource);
     ASSERT(resource == m_mainResource);
-    ASSERT(m_state != State::Initialized);
 
-    if (m_state == State::Filtering)
-        willSendRequest(request, redirectResponse);
+    if (resource->errorOccurred())
+        return true;
 
-    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, "ContentFilter will finish filtering main resource at <%s>.\n", resource->url().string().ascii().data());
-
-    if (resource->errorOccurred()) {
-        m_documentLoader.notifyFinished(resource);
-        return;
-    }
-
     if (m_state == State::Filtering) {
+        LOG(ContentFiltering, "ContentFilter will finish filtering main resource at <%s>.\n", resource->url().string().ascii().data());
         forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) {
             contentFilter.finishedAddingData();
         });
 
-        if (m_state != State::Blocked)
+        if (m_state != State::Blocked) {
+            m_state = State::Allowed;
             deliverResourceData(*resource);
-        
+        }
+
         if (m_state == State::Stopped)
-            return;
+            return false;
     }
 
-    if (m_state != State::Blocked)
-        m_documentLoader.notifyFinished(resource);
+    return m_state != State::Blocked;
 }
 
 void ContentFilter::forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)> function)
@@ -267,11 +235,13 @@
     ASSERT(state == State::Allowed || state == State::Blocked);
     LOG(ContentFiltering, "ContentFilter decided load should be %s for main resource at <%s>.\n", state == State::Allowed ? "allowed" : "blocked", m_mainResource ? m_mainResource->url().string().ascii().data() : "");
     m_state = state;
-    m_documentLoader.contentFilterDidDecide();
+    if (m_state == State::Blocked)
+        m_documentLoader.contentFilterDidBlock();
 }
 
 void ContentFilter::deliverResourceData(CachedResource& resource)
 {
+    ASSERT(m_state == State::Allowed);
     ASSERT(resource.dataBufferingPolicy() == BufferData);
     if (auto* resourceBuffer = resource.resourceBuffer())
         m_documentLoader.dataReceived(&resource, resourceBuffer->data(), resourceBuffer->size());

Modified: trunk/Source/WebCore/loader/ContentFilter.h (194949 => 194950)


--- 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)
@@ -28,7 +28,6 @@
 
 #if ENABLE(CONTENT_FILTERING)
 
-#include "CachedRawResourceClient.h"
 #include "CachedResourceHandle.h"
 #include <functional>
 #include <wtf/Vector.h>
@@ -39,39 +38,43 @@
 class ContentFilterUnblockHandler;
 class DocumentLoader;
 class PlatformContentFilter;
+class ResourceRequest;
+class ResourceResponse;
 class SharedBuffer;
 
-class ContentFilter final : private CachedRawResourceClient {
+class ContentFilter {
     WTF_MAKE_FAST_ALLOCATED;
     WTF_MAKE_NONCOPYABLE(ContentFilter);
 
 public:
     template <typename T> static void addType() { types().append(type<T>()); }
 
-    static std::unique_ptr<ContentFilter> createIfEnabled(DocumentLoader&);
-    ~ContentFilter() override;
+    static std::unique_ptr<ContentFilter> create(DocumentLoader&);
+    ~ContentFilter();
 
     static const char* urlScheme() { return "x-apple-content-filter"; }
 
-    void willSendRequest(ResourceRequest&, const ResourceResponse&);
     void startFilteringMainResource(CachedRawResource&);
     void stopFilteringMainResource();
 
+    bool continueAfterWillSendRequest(ResourceRequest&, const ResourceResponse&);
+    bool continueAfterResponseReceived(CachedResource*, const ResourceResponse&);
+    bool continueAfterDataReceived(CachedResource*, const char* data, int length);
+    bool continueAfterNotifyFinished(CachedResource*);
+
+    ContentFilterUnblockHandler unblockHandler() const;
+    Ref<SharedBuffer> replacementData() const;
+    String unblockRequestDeniedScript() const;
+
+private:
     enum class State {
-        Initialized,
+        Stopped,
         Filtering,
         Allowed,
         Blocked,
-        Stopped
     };
-    State state() const { return m_state; }
-    ContentFilterUnblockHandler unblockHandler() const;
-    Ref<SharedBuffer> replacementData() const;
-    String unblockRequestDeniedScript() const;
 
-private:
     struct Type {
-        const std::function<bool()> enabled;
         const std::function<std::unique_ptr<PlatformContentFilter>()> create;
     };
     template <typename T> static Type type();
@@ -81,14 +84,6 @@
     friend std::unique_ptr<ContentFilter> std::make_unique<ContentFilter>(Container&&, DocumentLoader&);
     ContentFilter(Container, DocumentLoader&);
 
-    // CachedRawResourceClient
-    void responseReceived(CachedResource*, const ResourceResponse&) override;
-    void dataReceived(CachedResource*, const char* data, int length) override;
-    void redirectReceived(CachedResource*, ResourceRequest&, const ResourceResponse&) override;
-
-    // CachedResourceClient
-    void notifyFinished(CachedResource*) override;
-
     void forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)>);
     void didDecide(State);
     void deliverResourceData(CachedResource&);
@@ -97,14 +92,14 @@
     DocumentLoader& m_documentLoader;
     CachedResourceHandle<CachedRawResource> m_mainResource;
     PlatformContentFilter* m_blockingContentFilter { nullptr };
-    State m_state { State::Initialized };
+    State m_state { State::Stopped };
 };
 
 template <typename T>
 ContentFilter::Type ContentFilter::type()
 {
     static_assert(std::is_base_of<PlatformContentFilter, T>::value, "Type must be a PlatformContentFilter.");
-    return { T::enabled, T::create };
+    return { T::create };
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (194949 => 194950)


--- 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)
@@ -370,6 +370,11 @@
 
 void DocumentLoader::notifyFinished(CachedResource* resource)
 {
+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilter && !m_contentFilter->continueAfterNotifyFinished(resource))
+        return;
+#endif
+
     ASSERT_UNUSED(resource, m_mainResource == resource);
     ASSERT(m_mainResource);
     if (!m_mainResource->errorOccurred() && !m_mainResource->wasCanceled()) {
@@ -540,11 +545,8 @@
     }
 
 #if ENABLE(CONTENT_FILTERING)
-    if (m_contentFilter && redirectResponse.isNull()) {
-        m_contentFilter->willSendRequest(newRequest, redirectResponse);
-        if (newRequest.isNull())
-            return;
-    }
+    if (m_contentFilter && !m_contentFilter->continueAfterWillSendRequest(newRequest, redirectResponse))
+        return;
 #endif
 
     setRequest(newRequest);
@@ -606,6 +608,11 @@
 
 void DocumentLoader::responseReceived(CachedResource* resource, const ResourceResponse& response)
 {
+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilter && !m_contentFilter->continueAfterResponseReceived(resource, response))
+        return;
+#endif
+
     ASSERT_UNUSED(resource, m_mainResource == resource);
     Ref<DocumentLoader> protect(*this);
     bool willLoadFallback = m_applicationCacheHost->maybeLoadFallbackForMainResponse(request(), response);
@@ -873,6 +880,11 @@
 
 void DocumentLoader::dataReceived(CachedResource* resource, const char* data, int length)
 {
+#if ENABLE(CONTENT_FILTERING)
+    if (m_contentFilter && !m_contentFilter->continueAfterDataReceived(resource, data, length))
+        return;
+#endif
+
     ASSERT(data);
     ASSERT(length);
     ASSERT_UNUSED(resource, resource == m_mainResource);
@@ -1418,7 +1430,7 @@
         return;
 
 #if ENABLE(CONTENT_FILTERING)
-    m_contentFilter = !m_originalSubstituteDataWasValid ? ContentFilter::createIfEnabled(*this) : nullptr;
+    m_contentFilter = !m_substituteData.isValid() ? ContentFilter::create(*this) : nullptr;
 #endif
 
     // FIXME: Is there any way the extra fields could have not been added by now?
@@ -1624,11 +1636,8 @@
 void DocumentLoader::becomeMainResourceClient()
 {
 #if ENABLE(CONTENT_FILTERING)
-    if (m_contentFilter && m_contentFilter->state() == ContentFilter::State::Initialized) {
-        // ContentFilter will synthesize CachedRawResourceClient callbacks.
+    if (m_contentFilter)
         m_contentFilter->startFilteringMainResource(*m_mainResource);
-        return;
-    }
 #endif
     m_mainResource->addClient(this);
 }
@@ -1666,13 +1675,9 @@
     frameLoader()->client().contentFilterDidBlockLoad(WTFMove(unblockHandler));
 }
 
-void DocumentLoader::contentFilterDidDecide()
+void DocumentLoader::contentFilterDidBlock()
 {
-    using State = ContentFilter::State;
     ASSERT(m_contentFilter);
-    ASSERT(m_contentFilter->state() == State::Blocked || m_contentFilter->state() == State::Allowed);
-    if (m_contentFilter->state() == State::Allowed)
-        return;
 
     installContentFilterUnblockHandler(*m_contentFilter);
 

Modified: trunk/Source/WebCore/loader/DocumentLoader.h (194949 => 194950)


--- 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)
@@ -349,7 +349,7 @@
 #if ENABLE(CONTENT_FILTERING)
         friend class ContentFilter;
         void installContentFilterUnblockHandler(ContentFilter&);
-        void contentFilterDidDecide();
+        void contentFilterDidBlock();
 #endif
 
         Frame* m_frame;

Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h (194949 => 194950)


--- 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)
@@ -32,8 +32,6 @@
 #include <wtf/OSObjectPtr.h>
 #include <wtf/RetainPtr.h>
 
-#define HAVE_NETWORK_EXTENSION PLATFORM(IOS) || (PLATFORM(MAC) && CPU(X86_64))
-
 enum NEFilterSourceStatus : NSInteger;
 
 OBJC_CLASS NEFilterSource;
@@ -41,11 +39,12 @@
 
 namespace WebCore {
 
+class URL;
+
 class NetworkExtensionContentFilter final : public PlatformContentFilter {
     friend std::unique_ptr<NetworkExtensionContentFilter> std::make_unique<NetworkExtensionContentFilter>();
 
 public:
-    static bool enabled();
     static std::unique_ptr<NetworkExtensionContentFilter> create();
 
     void willSendRequest(ResourceRequest&, const ResourceResponse&) override;
@@ -58,7 +57,10 @@
     ContentFilterUnblockHandler unblockHandler() const override;
 
 private:
+    static bool enabled();
+
     NetworkExtensionContentFilter();
+    void initialize(const URL* = nullptr);
     void handleDecision(NEFilterSourceStatus, NSData *replacementData);
 
     NEFilterSourceStatus m_status;

Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm (194949 => 194950)


--- 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)
@@ -65,24 +65,36 @@
 
 NetworkExtensionContentFilter::NetworkExtensionContentFilter()
     : m_status { NEFilterSourceStatusNeedsMoreData }
-    , m_queue { adoptOSObject(dispatch_queue_create("com.apple.WebCore.NEFilterSourceQueue", DISPATCH_QUEUE_SERIAL)) }
-    , m_semaphore { adoptOSObject(dispatch_semaphore_create(0)) }
+{
+}
+
+void NetworkExtensionContentFilter::initialize(const URL* url)
+{
+    ASSERT(!m_queue);
+    ASSERT(!m_semaphore);
+    ASSERT(!m_neFilterSource);
+    m_queue = adoptOSObject(dispatch_queue_create("com.apple.WebCore.NEFilterSourceQueue", DISPATCH_QUEUE_SERIAL));
+    m_semaphore = adoptOSObject(dispatch_semaphore_create(0));
 #if HAVE(MODERN_NE_FILTER_SOURCE)
-    , m_neFilterSource { adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:m_queue.get()]) }
+    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]);
 #endif
-{
-    ASSERT([getNEFilterSourceClass() filterRequired]);
 }
 
 void NetworkExtensionContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
 {
 #if HAVE(MODERN_NE_FILTER_SOURCE)
     ASSERT(!request.isNull());
-    if (!request.url().protocolIsInHTTPFamily()) {
+    if (!request.url().protocolIsInHTTPFamily() || !enabled()) {
         m_status = NEFilterSourceStatusPass;
         return;
     }
 
+    initialize();
+
     if (!redirectResponse.isNull()) {
         responseReceived(redirectResponse);
         if (!needsMoreData())
@@ -125,8 +137,12 @@
     }
 
 #if !HAVE(MODERN_NE_FILTER_SOURCE)
-    ASSERT(!m_neFilterSource);
-    m_neFilterSource = adoptNS([allocNEFilterSourceInstance() initWithURL:response.url() direction:NEFilterSourceDirectionInbound socketIdentifier:0]);
+    if (!enabled()) {
+        m_status = NEFilterSourceStatusPass;
+        return;
+    }
+
+    initialize(&response.url());
 #else
     [m_neFilterSource receivedResponse:response.nsURLResponse() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
         handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));

Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h (194949 => 194950)


--- 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)
@@ -39,7 +39,6 @@
     friend std::unique_ptr<ParentalControlsContentFilter> std::make_unique<ParentalControlsContentFilter>();
 
 public:
-    static bool enabled();
     static std::unique_ptr<ParentalControlsContentFilter> create();
 
     void willSendRequest(ResourceRequest&, const ResourceResponse&) override { }
@@ -52,6 +51,8 @@
     ContentFilterUnblockHandler unblockHandler() const override;
 
 private:
+    static bool enabled();
+
     ParentalControlsContentFilter();
     void updateFilterState();
 

Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm (194949 => 194950)


--- 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)
@@ -56,7 +56,6 @@
 ParentalControlsContentFilter::ParentalControlsContentFilter()
     : m_filterState { kWFEStateBuffering }
 {
-    ASSERT([getWebFilterEvaluatorClass() isManagedSession]);
 }
 
 static inline bool canHandleResponse(const ResourceResponse& response)
@@ -72,7 +71,7 @@
 {
     ASSERT(!m_webFilterEvaluator);
 
-    if (!canHandleResponse(response)) {
+    if (!canHandleResponse(response) || !enabled()) {
         m_filterState = kWFEStateAllowed;
         return;
     }

Modified: trunk/Source/WebCore/testing/MockContentFilter.cpp (194949 => 194950)


--- 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)
@@ -70,6 +70,11 @@
 
 void MockContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
 {
+    if (!enabled()) {
+        m_status = Status::Allowed;
+        return;
+    }
+
     if (redirectResponse.isNull())
         maybeDetermineStatus(DecisionPoint::AfterWillSendRequest);
     else

Modified: trunk/Source/WebCore/testing/MockContentFilter.h (194949 => 194950)


--- 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)
@@ -36,7 +36,6 @@
 
 public:
     static void ensureInstalled();
-    static bool enabled();
     static std::unique_ptr<MockContentFilter> create();
 
     void willSendRequest(ResourceRequest&, const ResourceResponse&) override;
@@ -56,6 +55,8 @@
         Blocked
     };
 
+    static bool enabled();
+
     MockContentFilter() = default;
     void maybeDetermineStatus(MockContentFilterSettings::DecisionPoint);
 

Modified: trunk/Tools/ChangeLog (194949 => 194950)


--- trunk/Tools/ChangeLog	2016-01-13 01:41:48 UTC (rev 194949)
+++ trunk/Tools/ChangeLog	2016-01-13 02:07:11 UTC (rev 194950)
@@ -1,3 +1,47 @@
+2016-01-08  Andy Estes  <[email protected]>
+
+        [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]):
+
 2016-01-12  Dewei Zhu  <[email protected]>
 
         Fix the Sunpider converage in slow device.

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (194949 => 194950)


--- 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)
@@ -278,6 +278,7 @@
 		A14FC5881B8991BF00D107EB /* ContentFiltering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5861B8991B600D107EB /* ContentFiltering.mm */; };
 		A14FC58B1B89927100D107EB /* ContentFilteringPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */; };
 		A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC58E1B8AE36500D107EB /* TestProtocol.mm */; };
+		A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */; };
 		A1C4FB6E1BACCE50003742D0 /* QuickLook.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1C4FB6C1BACCE50003742D0 /* QuickLook.mm */; };
 		A1C4FB731BACD1CA003742D0 /* pages.pages in Copy Resources */ = {isa = PBXBuildFile; fileRef = A1C4FB721BACD1B7003742D0 /* pages.pages */; };
 		A1DF74321C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */; };
@@ -378,6 +379,7 @@
 			dstPath = TestWebKitAPI.resources;
 			dstSubfolderSpec = 7;
 			files = (
+				A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */,
 				CDC8E4941BC6F10800594FEC /* video-with-audio.html in Copy Resources */,
 				CDC8E4951BC6F10800594FEC /* video-with-audio.mp4 in Copy Resources */,
 				CDC8E4961BC6F10800594FEC /* video-without-audio.html in Copy Resources */,
@@ -671,6 +673,8 @@
 		A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentFilteringPlugIn.mm; sourceTree = "<group>"; };
 		A14FC58D1B8AE36500D107EB /* TestProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProtocol.h; path = cocoa/TestProtocol.h; sourceTree = "<group>"; };
 		A14FC58E1B8AE36500D107EB /* TestProtocol.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestProtocol.mm; path = cocoa/TestProtocol.mm; sourceTree = "<group>"; };
+		A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ContentFiltering.html; sourceTree = "<group>"; };
+		A18AA8CC1C3FA218009B2B97 /* ContentFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentFiltering.h; sourceTree = "<group>"; };
 		A1A4FE5D18DD3DB700B5EA8A /* Download.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Download.mm; sourceTree = "<group>"; };
 		A1C4FB6C1BACCE50003742D0 /* QuickLook.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QuickLook.mm; sourceTree = "<group>"; };
 		A1C4FB721BACD1B7003742D0 /* pages.pages */ = {isa = PBXFileReference; lastKnownFileType = file; name = pages.pages; path = ios/pages.pages; sourceTree = SOURCE_ROOT; };
@@ -928,10 +932,12 @@
 		1ABC3DEC1899BE55004F0626 /* WebKit2 Cocoa */ = {
 			isa = PBXGroup;
 			children = (
+				A16F66B81C40E9E100BD4D24 /* Resources */,
 				7CEFA9641AC0B9E200B910FD /* _WKUserContentExtensionStore.mm */,
 				2DD355351BD08378005DF4A7 /* AutoLayoutIntegration.mm */,
 				A13EBBAC1B87436F00097110 /* BundleParameters.mm */,
 				A13EBBAE1B87436F00097110 /* BundleParametersPlugIn.mm */,
+				A18AA8CC1C3FA218009B2B97 /* ContentFiltering.h */,
 				A14FC5861B8991B600D107EB /* ContentFiltering.mm */,
 				A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */,
 				A1A4FE5D18DD3DB700B5EA8A /* Download.mm */,
@@ -1020,6 +1026,14 @@
 			path = cocoa/WebProcessPlugIn;
 			sourceTree = "<group>";
 		};
+		A16F66B81C40E9E100BD4D24 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */,
+			);
+			name = Resources;
+			sourceTree = "<group>";
+		};
 		A1C4FB6F1BACCEFA003742D0 /* Resources */ = {
 			isa = PBXGroup;
 			children = (

Modified: trunk/Tools/TestWebKitAPI/Tests/CustomProtocolsSyncXHRTest.mm (194949 => 194950)


--- 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)
@@ -48,8 +48,7 @@
 
 TEST(WebKit2CustomProtocolsTest, SyncXHR)
 {
-    [NSURLProtocol registerClass:[TestProtocol class]];
-    [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
+    [TestProtocol registerWithScheme:@"http"];
 
     RetainPtr<WKProcessGroup> processGroup = adoptNS([[WKProcessGroup alloc] init]);
     RetainPtr<WKBrowsingContextGroup> browsingContextGroup = adoptNS([[WKBrowsingContextGroup alloc] initWithIdentifier:@"TestIdentifier"]);
@@ -69,8 +68,7 @@
     WKPageLoadURL(wkView.get().pageRef, Util::createURLForResource("custom-protocol-sync-xhr", "html"));
 
     TestWebKitAPI::Util::run(&testFinished);
-    [NSURLProtocol unregisterClass:[TestProtocol class]];
-    [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
+    [TestProtocol unregister];
 }
 
 } // namespace TestWebKitAPI

Copied: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h (from rev 194935, trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h) (0 => 194950)


--- 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)
@@ -0,0 +1,28 @@
+/*
+ * 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 <NSObject>
+- (void)checkIfPlatformFrameworksAreLoaded:(void (^)(BOOL parentalControlsLoaded, BOOL networkExtensionLoaded))completionHandler;
+@end

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html (0 => 194950)


--- 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)
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+PASS
+</body>
+</html>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.mm (194949 => 194950)


--- 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)
@@ -25,17 +25,19 @@
 
 #import "config.h"
 
-#if WK_API_ENABLED && PLATFORM(MAC)
+#if WK_API_ENABLED
 
+#import "ContentFiltering.h"
 #import "MockContentFilterSettings.h"
 #import "PlatformUtilities.h"
 #import "TestProtocol.h"
 #import "WKWebViewConfigurationExtras.h"
-#import <WebKit/WKBrowsingContextController.h>
 #import <WebKit/WKNavigationDelegatePrivate.h>
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKWebView.h>
 #import <WebKit/_WKDownloadDelegate.h>
+#import <WebKit/_WKRemoteObjectInterface.h>
+#import <WebKit/_WKRemoteObjectRegistry.h>
 #import <wtf/RetainPtr.h>
 
 using Decision = WebCore::MockContentFilterSettings::Decision;
@@ -118,8 +120,7 @@
 TEST(ContentFiltering, URLAfterServerRedirect)
 {
     @autoreleasepool {
-        [NSURLProtocol registerClass:[TestProtocol class]];
-        [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
+        [TestProtocol registerWithScheme:@"http"];
 
         auto configuration = configurationWithContentFilterSettings(Decision::Allow, DecisionPoint::AfterAddData);
         auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
@@ -128,8 +129,7 @@
         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://redirect?pass"]]];
         TestWebKitAPI::Util::run(&isDone);
 
-        [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
-        [NSURLProtocol unregisterClass:[TestProtocol class]];
+        [TestProtocol unregister];
     }
 }
 
@@ -172,8 +172,7 @@
 static void downloadTest(Decision decision, DecisionPoint decisionPoint)
 {
     @autoreleasepool {
-        [NSURLProtocol registerClass:[TestProtocol class]];
-        [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
+        [TestProtocol registerWithScheme:@"http"];
 
         auto configuration = configurationWithContentFilterSettings(decision, decisionPoint);
         auto downloadDelegate = adoptNS([[ContentFilteringDownloadDelegate alloc] init]);
@@ -193,8 +192,7 @@
 
         EXPECT_EQ(downloadShouldStart, downloadDidStart);
 
-        [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
-        [NSURLProtocol unregisterClass:[TestProtocol class]];
+        [TestProtocol unregister];
     }
 }
 
@@ -258,4 +256,107 @@
     downloadTest(Decision::Block, DecisionPoint::Never);
 }
 
+@interface LazilyLoadPlatformFrameworksController : NSObject <WKNavigationDelegate>
+@property (nonatomic, readonly) WKWebView *webView;
+- (void)expectParentalControlsLoaded:(BOOL)parentalControlsShouldBeLoaded networkExtensionLoaded:(BOOL)networkExtensionShouldBeLoaded;
+@end
+
+@implementation LazilyLoadPlatformFrameworksController {
+    RetainPtr<WKWebView> _webView;
+    RetainPtr<id <ContentFilteringProtocol>> _remoteObjectProxy;
+}
+
+- (instancetype)init
+{
+    if (!(self = [super init]))
+        return nil;
+
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration testwebkitapi_configurationWithTestPlugInClassName:@"ContentFilteringPlugIn"];
+    _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<bool>(parentalControlsShouldBeLoaded), static_cast<bool>(parentalControlsLoaded));
+#endif
+#if HAVE(NETWORK_EXTENSION)
+        EXPECT_EQ(static_cast<bool>(networkExtensionShouldBeLoaded), static_cast<bool>(networkExtensionLoaded));
+#endif
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&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:@"PASS" baseURL:[NSURL URLWithString:@"about:blank"]];
+        TestWebKitAPI::Util::run(&isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        [[controller webView] loadData:[NSData dataWithBytes:"PASS" length:4] MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"about:blank"]];
+        TestWebKitAPI::Util::run(&isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"ContentFiltering" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+        [[controller webView] loadFileURL:fileURL allowingReadAccessToURL:fileURL];
+        TestWebKitAPI::Util::run(&isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+
+        isDone = false;
+        [TestProtocol registerWithScheme:@"custom"];
+        [[controller webView] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"custom://test"]]];
+        TestWebKitAPI::Util::run(&isDone);
+        [controller expectParentalControlsLoaded:NO networkExtensionLoaded:NO];
+        [TestProtocol unregister];
+
+        isDone = false;
+        [TestProtocol registerWithScheme:@"http"];
+        [[controller webView] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://test"]]];
+        TestWebKitAPI::Util::run(&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:@"https"];
+        [[controller webView] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://test"]]];
+        TestWebKitAPI::Util::run(&isDone);
+        [controller expectParentalControlsLoaded:YES networkExtensionLoaded:YES];
+        [TestProtocol unregister];
+#endif
+    }
+}
+
 #endif // WK_API_ENABLED

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFilteringPlugIn.mm (194949 => 194950)


--- 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)
@@ -27,8 +27,13 @@
 
 #if WK_API_ENABLED
 
+#import "ContentFiltering.h"
 #import "MockContentFilterSettings.h"
 #import <WebKit/WKWebProcessPlugIn.h>
+#import <WebKit/WKWebProcessPlugInBrowserContextControllerPrivate.h>
+#import <WebKit/_WKRemoteObjectInterface.h>
+#import <WebKit/_WKRemoteObjectRegistry.h>
+#import <mach-o/dyld.h>
 
 using MockContentFilterSettings = WebCore::MockContentFilterSettings;
 using Decision = MockContentFilterSettings::Decision;
@@ -73,7 +78,7 @@
 
 @end
 
-@interface ContentFilteringPlugIn : NSObject <WKWebProcessPlugIn>
+@interface ContentFilteringPlugIn : NSObject <ContentFilteringProtocol, WKWebProcessPlugIn>
 @end
 
 @implementation ContentFilteringPlugIn {
@@ -88,6 +93,12 @@
     [plugInController.parameters addObserver:self forKeyPath:NSStringFromClass([MockContentFilterEnabler class]) options:NSKeyValueObservingOptionInitial context:NULL];
 }
 
+- (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController didCreateBrowserContextController:(WKWebProcessPlugInBrowserContextController *)browserContextController
+{
+    _WKRemoteObjectInterface *interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ContentFilteringProtocol)];
+    [[browserContextController _remoteObjectRegistry] registerExportedObject:self interface:interface];
+}
+
 - (void)dealloc
 {
     [[_plugInController parameters] removeObserver:self forKeyPath:NSStringFromClass([MockContentFilterEnabler class])];
@@ -97,10 +108,24 @@
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
 {
     id contentFilterEnabler = [object valueForKeyPath:keyPath];
-    ASSERT([contentFilterEnabler isKindOfClass:[MockContentFilterEnabler class]]);
+    ASSERT(!contentFilterEnabler || [contentFilterEnabler isKindOfClass:[MockContentFilterEnabler class]]);
     _contentFilterEnabler = contentFilterEnabler;
 }
 
+- (void)checkIfPlatformFrameworksAreLoaded:(void (^)(BOOL parentalControlsLoaded, BOOL networkExtensionLoaded))completionHandler
+{
+    bool parentalControlsLoaded = false;
+#if HAVE(PARENTAL_CONTROLS)
+    parentalControlsLoaded = NSVersionOfRunTimeLibrary("WebContentAnalysis") != -1;
+#endif
+    
+    bool networkExtensionLoaded = false;
+#if HAVE(NETWORK_EXTENSION)
+    networkExtensionLoaded = NSVersionOfRunTimeLibrary("NetworkExtension") != -1;
+#endif
+    completionHandler(parentalControlsLoaded, networkExtensionLoaded);
+}
+
 @end
 
 #endif // WK_API_ENABLED

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsTest.mm (194949 => 194950)


--- 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)
@@ -70,8 +70,7 @@
 
 TEST(WebKit2CustomProtocolsTest, MainResource)
 {
-    [NSURLProtocol registerClass:[TestProtocol class]];
-    [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
+    [TestProtocol registerWithScheme:@"http"];
 
     RetainPtr<WKProcessGroup> processGroup = adoptNS([[WKProcessGroup alloc] init]);
     RetainPtr<WKBrowsingContextGroup> browsingContextGroup = adoptNS([[WKBrowsingContextGroup alloc] initWithIdentifier:@"TestIdentifier"]);
@@ -81,8 +80,7 @@
     [[wkView browsingContextController] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://redirect?test", [TestProtocol scheme]]]]];
 
     Util::run(&testFinished);
-    [NSURLProtocol unregisterClass:[TestProtocol class]];
-    [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
+    [TestProtocol unregister];
 }
 
 } // namespace TestWebKitAPI

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing.mm (194949 => 194950)


--- 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)
@@ -32,7 +32,6 @@
 #import "PlatformUtilities.h"
 #import "PlatformWebView.h"
 #import "TestBrowsingContextLoadDelegate.h"
-#import "TestProtocol.h"
 #import <WebKit/WKViewPrivate.h>
 
 #if WK_API_ENABLED && PLATFORM(MAC)
@@ -43,9 +42,6 @@
 
 TEST(WebKit2, PreventImageLoadWithAutoResizingTest)
 {
-    [NSURLProtocol registerClass:[TestProtocol class]];
-    [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
-
     WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("DenyWillSendRequestTest"));
     PlatformWebView webView(context.get());
 
@@ -56,8 +52,6 @@
     [webView.platformView().browsingContextController loadHTMLString:@"<html><body style='background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAFZJREFUeF59z4EJADEIQ1F36k7u5E7ZKXeUQPACJ3wK7UNokVxVk9kHnQH7bY9hbDyDhNXgjpRLqFlo4M2GgfyJHhjq8V4agfrgPQX3JtJQGbofmCHgA/nAKks+JAjFAAAAAElFTkSuQmCC);'></body></html>" baseURL:[NSURL URLWithString:@"about:blank"]];
 
     Util::run(&testFinished);
-    [NSURLProtocol unregisterClass:[TestProtocol class]];
-    [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
 }
 
 } // namespace TestWebKitAPI

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.h (194949 => 194950)


--- 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)
@@ -28,6 +28,8 @@
 
 @interface TestProtocol : NSURLProtocol {
 }
++ (void)registerWithScheme:(NSString *)scheme;
++ (void)unregister;
 + (NSString *)scheme;
 @end
 

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestProtocol.mm (194949 => 194950)


--- 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)
@@ -26,11 +26,10 @@
 #import "config.h"
 #import "TestProtocol.h"
 
+#import <WebKit/WKBrowsingContextController.h>
 #import <wtf/RetainPtr.h>
 
-// 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 = @"http";
+static NSString *testScheme;
 
 @implementation TestProtocol
 
@@ -54,6 +53,25 @@
     return testScheme;
 }
 
++ (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;
+}
+
 - (void)startLoading
 {
     NSURL *requestURL = self.request.URL;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to