Title: [182356] trunk
Revision
182356
Author
aes...@apple.com
Date
2015-04-05 00:52:14 -0700 (Sun, 05 Apr 2015)

Log Message

[Content Filtering] Blocked page is not always displayed when it should be
https://bugs.webkit.org/show_bug.cgi?id=143410
Source/WebCore:

rdar://problem/20211099

Reviewed by Andreas Kling.

These tests now pass: contentfiltering/block-after-add-data.html
                      contentfiltering/block-after-response.html

There were several problems with how ContentFilter loaded replacement data:
(1) Replacement data was delivered to DocumentLoader as if it were the original document's data. This assumes
    that the original data was a UTF-8 encoded HTML document, which is not always true. We had a way to reset
    the encoding, but not the content type.
(2) Replacement data was never delivered when the filter blocks in DocumentLoader::responseReceived().
(3) The main resource load was cancelled before the replacement data could be rendered when the filter blocks
    in DocumentLoader::dataReceived().
The result was that only when the load was blocked after DocumentLoader::notifyFinished() would the replacement
data be shown properly, and only when problem (1) wasn't occurring.

This patch addresses these issues by using the substitute data mechanism to deliver replacement data. By using
substitute data, we can ensure that the original load is cancelled at the earliest opportunity and that the
replacement data is loaded with the proper content type and encoding.

Accomplishing this required changing the way ContentFilter interacts with DocumentLoader. Instead of placing
ContentFilter hooks throughout DocumentLoader, this patch makes ContentFilter itself the client of the
CachedRawResource for the duration of the filtering. If the filter decides to allow the load, DocumentLoader
adds itself as a client causing CachedRawResource to deliver to it the response and buffered data. If the
filter decides to block the load, DocumentLoader schedules a substitute data load. An added benefit of this
approach is that ContentFilter can reuse CachedRawResource's original data buffer instead of keeping its own.

* loader/ContentFilter.cpp:
(WebCore::ContentFilter::createIfNeeded): Changed to take a DecisionFunction rather than a ResourceResponse and DocumentLoader.
(WebCore::ContentFilter::ContentFilter): Ditto.
(WebCore::ContentFilter::~ContentFilter): Removed ourself as a CachedRawResource client if needed.
(WebCore::ContentFilter::startFilteringMainResource): Became the client of the CachedRawResource in order to start the filtering process.
(WebCore::ContentFilter::unblockHandler): Returned the unblock handler.
(WebCore::ContentFilter::replacementData): Returned the replacement data.
(WebCore::ContentFilter::unblockRequestDeniedScript): Returned the unblock request denied script.
(WebCore::ContentFilter::responseReceived): Called responseReceived() on each filter using forEachContentFilterUntilBlocked().
(WebCore::ContentFilter::dataReceived): Ditto for dataReceived().
(WebCore::ContentFilter::notifyFinished): Ditto for finishedLoading().
(WebCore::ContentFilter::forEachContentFilterUntilBlocked): For each filter that needs more data, called the function.
If the filter blocked the load, called didDecide() with State::Blocked.
If all filters allowed the load, called didDecide() with State::Allowed.
(WebCore::ContentFilter::didDecide): Set m_state and called m_decisionFunction().
(WebCore::ContentFilter::addData): Deleted.
(WebCore::ContentFilter::finishedAddingData): Deleted.
(WebCore::ContentFilter::needsMoreData): Deleted.
(WebCore::ContentFilter::didBlockData): Deleted.
(WebCore::ContentFilter::getReplacementData): Deleted.
* loader/ContentFilter.h:
(WebCore::ContentFilter::type):
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::DocumentLoader): Called ContentFilter::createIfNeeded() if not loading substitute data.
(WebCore::DocumentLoader::finishedLoading): Removed old ContentFilter code.
(WebCore::DocumentLoader::responseReceived): Ditto.
(WebCore::DocumentLoader::commitData): Ditto.
(WebCore::DocumentLoader::dataReceived): Ditto.
(WebCore::DocumentLoader::detachFromFrame): Set m_contentFilter to nullptr.
(WebCore::DocumentLoader::startLoadingMainResource): Called becomeMainResourceClientIfFilterAllows() instead of
becoming m_mainResource's client.
(WebCore::DocumentLoader::clearMainResource): Set m_contentFilter to nullptr.
(WebCore::DocumentLoader::becomeMainResourceClientIfFilterAllows): If ContentFilter is initialized, called
ContentFilter::startFilteringMainResource(). Otherwise added ourself as a client of m_mainResource.
(WebCore::DocumentLoader::installContentFilterUnblockHandler): Added a helper for creating and notifying
FrameLoaderClient of the unblock handler.
(WebCore::DocumentLoader::contentFilterDidDecide): Set m_contentFilter to nullptr. If the content filter
allowed the load, then added ourself as the CachedRawResource's client. Otherwise, installed the unblock handler
and scheduled a substitute data load with the replacement data.
* loader/DocumentLoader.h:
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::prepareForLoadStart): Removed call to PolicyChecker::prepareForLoadStart().
* loader/NavigationScheduler.cpp:
(WebCore::ScheduledSubstituteDataLoad::ScheduledSubstituteDataLoad): Added a ScheduledNavigation subclass that
calls FrameLoader::load() with a FrameLoadRequest containing substitute data.
(WebCore::NavigationScheduler::scheduleSubstituteDataLoad): Scheduled a substitute data load.
* loader/NavigationScheduler.h:
* loader/PolicyChecker.cpp:
(WebCore::PolicyChecker::checkNavigationPolicy): Reset m_contentFilterUnblockHandler if it couldn't handle the request.
(WebCore::PolicyChecker::prepareForLoadStart): Deleted.
* loader/PolicyChecker.h:
* platform/ContentFilterUnblockHandler.h:
(WebCore::ContentFilterUnblockHandler::unreachableURL):
(WebCore::ContentFilterUnblockHandler::setUnreachableURL):
(WebCore::ContentFilterUnblockHandler::unblockURLScheme): Renamed to ContentFilter::urlScheme().
* platform/PlatformContentFilter.h:
* platform/cocoa/ContentFilterUnblockHandlerCocoa.mm:
(WebCore::ContentFilterUnblockHandler::wrapWithDecisionHandler): Added a helper to wrap the unblock handler with an outer DecisionHandlerFunction.
(WebCore::ContentFilterUnblockHandler::encode): Added m_unreachableURL to the encoding.
(WebCore::ContentFilterUnblockHandler::decode): Ditto for the decoding.
(WebCore::ContentFilterUnblockHandler::canHandleRequest): Changed to call ContentFilter::urlScheme().
* platform/cocoa/NetworkExtensionContentFilter.h:
* platform/cocoa/NetworkExtensionContentFilter.mm:
(replacementDataFromDecisionInfo): Added a helper to extract replacement data from the decisionInfo dictionary.
(WebCore::NetworkExtensionContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled.
(WebCore::NetworkExtensionContentFilter::create): Created a new object.
(WebCore::NetworkExtensionContentFilter::NetworkExtensionContentFilter): Created a NEFilterSource immediately when using the modern API.
(WebCore::NetworkExtensionContentFilter::responseReceived): Created a NEFilterSource when using the legacy API.
Called -[NEFilterSource receivedResponse:decisionHandler:] when using the modern API.
(WebCore::NetworkExtensionContentFilter::addData): Stopped buffering the original data.
(WebCore::NetworkExtensionContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&.
(WebCore::NetworkExtensionContentFilter::canHandleResponse): Deleted.
(WebCore::createNEFilterSource): Deleted.
(WebCore::NetworkExtensionContentFilter::getReplacementData): Deleted.
* platform/cocoa/ParentalControlsContentFilter.h:
* platform/cocoa/ParentalControlsContentFilter.mm:
(WebCore::ParentalControlsContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled.
(WebCore::ParentalControlsContentFilter::create): Created a new object.
(WebCore::ParentalControlsContentFilter::ParentalControlsContentFilter): Initialized m_filterState to kWFEStateBuffering.
(WebCore::canHandleResponse): Added a helper to check if the response can be filtered.
(WebCore::ParentalControlsContentFilter::responseReceived): If !canHandleResponse(), set m_filterState to kWFEStateAllowed and return.
Otherwise created a new WebFilterEvaluator with the response.
(WebCore::ParentalControlsContentFilter::addData): Called updateFilterState().
(WebCore::ParentalControlsContentFilter::finishedAddingData): Ditto.
(WebCore::ParentalControlsContentFilter::needsMoreData): Changed to check m_filterState.
(WebCore::ParentalControlsContentFilter::didBlockData): Ditto.
(WebCore::ParentalControlsContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&.
(WebCore::ParentalControlsContentFilter::updateFilterState): Updated m_filterState by calling -[WebFilterEvaluator filterState].
(WebCore::ParentalControlsContentFilter::canHandleResponse): Deleted.
(WebCore::ParentalControlsContentFilter::getReplacementData): Deleted.
* platform/spi/cocoa/NEFilterSourceSPI.h:
* platform/spi/cocoa/WebFilterEvaluatorSPI.h:
* testing/MockContentFilter.cpp:
(WebCore::MockContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled.
(WebCore::MockContentFilter::create): Created a new object.
(WebCore::MockContentFilter::responseReceived): Called maybeDetermineStatus().
(WebCore::MockContentFilter::addData): Stopped buffering the original data.
(WebCore::MockContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&.
(WebCore::MockContentFilter::unblockHandler): Asserted that we blocked data.
(WebCore::MockContentFilter::canHandleResponse): Deleted.
(WebCore::MockContentFilter::MockContentFilter): Deleted.
(WebCore::MockContentFilter::getReplacementData): Deleted.
* testing/MockContentFilter.h:
* testing/MockContentFilterSettings.cpp:
(WebCore::MockContentFilterSettings::unblockRequestURL): Changed to use a StringBuilder.

Source/WebKit2:

Reviewed by Andreas Kling.

* UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::didStartProvisionalLoad): Stopped clearing m_contentFilterUnblockHandler here.
(WebKit::WebFrameProxy::didHandleContentFilterUnblockNavigation): Started doing it here instead.

LayoutTests:

Reviewed by Andreas Kling.

* TestExpectations: Unskipped block-after-add-data.html.
* contentfiltering/block-after-add-data-expected.html: Added a passing expectation.
* contentfiltering/block-after-response-expected.html: Ditto.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (182355 => 182356)


--- trunk/LayoutTests/ChangeLog	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/LayoutTests/ChangeLog	2015-04-05 07:52:14 UTC (rev 182356)
@@ -1,3 +1,14 @@
+2015-04-04  Andy Estes  <aes...@apple.com>
+
+        [Content Filtering] Blocked page is not always displayed when it should be
+        https://bugs.webkit.org/show_bug.cgi?id=143410
+
+        Reviewed by Andreas Kling.
+
+        * TestExpectations: Unskipped block-after-add-data.html.
+        * contentfiltering/block-after-add-data-expected.html: Added a passing expectation.
+        * contentfiltering/block-after-response-expected.html: Ditto.
+
 2015-04-04  Chris Fleizach  <cfleiz...@apple.com>
 
         AX: Heuristic: Avoid exposing an element as clickable if mouse event delegation is handled on an AXElement with more than one descendant AXElement

Modified: trunk/LayoutTests/TestExpectations (182355 => 182356)


--- trunk/LayoutTests/TestExpectations	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/LayoutTests/TestExpectations	2015-04-05 07:52:14 UTC (rev 182356)
@@ -497,9 +497,6 @@
 webkit.org/b/114280 svg/animations/smil-leak-element-instances.svg [ Pass Failure ]
 webkit.org/b/114280 svg/animations/smil-leak-elements.svg [ Pass Failure ]
 
-# contentfiltering/block-after-add-data.html times out unexpectedly
-webkit.org/b/142894 contentfiltering/block-after-add-data.html [ Skip ]
-
 webkit.org/b/143085 media/track/track-mode.html [ Pass Timeout ]
 
 # In ES6, Object type restrictions on a first parameter of several Object.* functions are relaxed.

Modified: trunk/LayoutTests/contentfiltering/block-after-add-data-expected.html (182355 => 182356)


--- trunk/LayoutTests/contentfiltering/block-after-add-data-expected.html	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/LayoutTests/contentfiltering/block-after-add-data-expected.html	2015-04-05 07:52:14 UTC (rev 182356)
@@ -1,2 +1,2 @@
 <!DOCTYPE html>
-<iframe src="" html><body>"></iframe>
+<iframe src="" html><body>PASS"></iframe>

Modified: trunk/LayoutTests/contentfiltering/block-after-response-expected.html (182355 => 182356)


--- trunk/LayoutTests/contentfiltering/block-after-response-expected.html	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/LayoutTests/contentfiltering/block-after-response-expected.html	2015-04-05 07:52:14 UTC (rev 182356)
@@ -1,2 +1,2 @@
 <!DOCTYPE html>
-<iframe src="" html><body>FAIL"></iframe>
+<iframe src="" html><body>PASS"></iframe>

Modified: trunk/Source/WebCore/ChangeLog (182355 => 182356)


--- trunk/Source/WebCore/ChangeLog	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/ChangeLog	2015-04-05 07:52:14 UTC (rev 182356)
@@ -1,3 +1,141 @@
+2015-04-04  Andy Estes  <aes...@apple.com>
+
+        [Content Filtering] Blocked page is not always displayed when it should be
+        https://bugs.webkit.org/show_bug.cgi?id=143410
+        rdar://problem/20211099
+
+        Reviewed by Andreas Kling.
+
+        These tests now pass: contentfiltering/block-after-add-data.html
+                              contentfiltering/block-after-response.html
+
+        There were several problems with how ContentFilter loaded replacement data:
+        (1) Replacement data was delivered to DocumentLoader as if it were the original document's data. This assumes
+            that the original data was a UTF-8 encoded HTML document, which is not always true. We had a way to reset
+            the encoding, but not the content type.
+        (2) Replacement data was never delivered when the filter blocks in DocumentLoader::responseReceived().
+        (3) The main resource load was cancelled before the replacement data could be rendered when the filter blocks
+            in DocumentLoader::dataReceived().
+        The result was that only when the load was blocked after DocumentLoader::notifyFinished() would the replacement
+        data be shown properly, and only when problem (1) wasn't occurring.
+
+        This patch addresses these issues by using the substitute data mechanism to deliver replacement data. By using
+        substitute data, we can ensure that the original load is cancelled at the earliest opportunity and that the
+        replacement data is loaded with the proper content type and encoding.
+
+        Accomplishing this required changing the way ContentFilter interacts with DocumentLoader. Instead of placing
+        ContentFilter hooks throughout DocumentLoader, this patch makes ContentFilter itself the client of the
+        CachedRawResource for the duration of the filtering. If the filter decides to allow the load, DocumentLoader
+        adds itself as a client causing CachedRawResource to deliver to it the response and buffered data. If the
+        filter decides to block the load, DocumentLoader schedules a substitute data load. An added benefit of this
+        approach is that ContentFilter can reuse CachedRawResource's original data buffer instead of keeping its own.
+
+        * loader/ContentFilter.cpp:
+        (WebCore::ContentFilter::createIfNeeded): Changed to take a DecisionFunction rather than a ResourceResponse and DocumentLoader.
+        (WebCore::ContentFilter::ContentFilter): Ditto.
+        (WebCore::ContentFilter::~ContentFilter): Removed ourself as a CachedRawResource client if needed.
+        (WebCore::ContentFilter::startFilteringMainResource): Became the client of the CachedRawResource in order to start the filtering process.
+        (WebCore::ContentFilter::unblockHandler): Returned the unblock handler.
+        (WebCore::ContentFilter::replacementData): Returned the replacement data.
+        (WebCore::ContentFilter::unblockRequestDeniedScript): Returned the unblock request denied script.
+        (WebCore::ContentFilter::responseReceived): Called responseReceived() on each filter using forEachContentFilterUntilBlocked().
+        (WebCore::ContentFilter::dataReceived): Ditto for dataReceived().
+        (WebCore::ContentFilter::notifyFinished): Ditto for finishedLoading().
+        (WebCore::ContentFilter::forEachContentFilterUntilBlocked): For each filter that needs more data, called the function.
+        If the filter blocked the load, called didDecide() with State::Blocked.
+        If all filters allowed the load, called didDecide() with State::Allowed.
+        (WebCore::ContentFilter::didDecide): Set m_state and called m_decisionFunction().
+        (WebCore::ContentFilter::addData): Deleted.
+        (WebCore::ContentFilter::finishedAddingData): Deleted.
+        (WebCore::ContentFilter::needsMoreData): Deleted.
+        (WebCore::ContentFilter::didBlockData): Deleted.
+        (WebCore::ContentFilter::getReplacementData): Deleted.
+        * loader/ContentFilter.h:
+        (WebCore::ContentFilter::type):
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::DocumentLoader): Called ContentFilter::createIfNeeded() if not loading substitute data.
+        (WebCore::DocumentLoader::finishedLoading): Removed old ContentFilter code.
+        (WebCore::DocumentLoader::responseReceived): Ditto.
+        (WebCore::DocumentLoader::commitData): Ditto.
+        (WebCore::DocumentLoader::dataReceived): Ditto.
+        (WebCore::DocumentLoader::detachFromFrame): Set m_contentFilter to nullptr.
+        (WebCore::DocumentLoader::startLoadingMainResource): Called becomeMainResourceClientIfFilterAllows() instead of
+        becoming m_mainResource's client.
+        (WebCore::DocumentLoader::clearMainResource): Set m_contentFilter to nullptr.
+        (WebCore::DocumentLoader::becomeMainResourceClientIfFilterAllows): If ContentFilter is initialized, called
+        ContentFilter::startFilteringMainResource(). Otherwise added ourself as a client of m_mainResource.
+        (WebCore::DocumentLoader::installContentFilterUnblockHandler): Added a helper for creating and notifying
+        FrameLoaderClient of the unblock handler.
+        (WebCore::DocumentLoader::contentFilterDidDecide): Set m_contentFilter to nullptr. If the content filter
+        allowed the load, then added ourself as the CachedRawResource's client. Otherwise, installed the unblock handler
+        and scheduled a substitute data load with the replacement data.
+        * loader/DocumentLoader.h:
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::prepareForLoadStart): Removed call to PolicyChecker::prepareForLoadStart().
+        * loader/NavigationScheduler.cpp:
+        (WebCore::ScheduledSubstituteDataLoad::ScheduledSubstituteDataLoad): Added a ScheduledNavigation subclass that
+        calls FrameLoader::load() with a FrameLoadRequest containing substitute data.
+        (WebCore::NavigationScheduler::scheduleSubstituteDataLoad): Scheduled a substitute data load.
+        * loader/NavigationScheduler.h:
+        * loader/PolicyChecker.cpp:
+        (WebCore::PolicyChecker::checkNavigationPolicy): Reset m_contentFilterUnblockHandler if it couldn't handle the request.
+        (WebCore::PolicyChecker::prepareForLoadStart): Deleted.
+        * loader/PolicyChecker.h:
+        * platform/ContentFilterUnblockHandler.h:
+        (WebCore::ContentFilterUnblockHandler::unreachableURL):
+        (WebCore::ContentFilterUnblockHandler::setUnreachableURL):
+        (WebCore::ContentFilterUnblockHandler::unblockURLScheme): Renamed to ContentFilter::urlScheme().
+        * platform/PlatformContentFilter.h:
+        * platform/cocoa/ContentFilterUnblockHandlerCocoa.mm:
+        (WebCore::ContentFilterUnblockHandler::wrapWithDecisionHandler): Added a helper to wrap the unblock handler with an outer DecisionHandlerFunction.
+        (WebCore::ContentFilterUnblockHandler::encode): Added m_unreachableURL to the encoding.
+        (WebCore::ContentFilterUnblockHandler::decode): Ditto for the decoding.
+        (WebCore::ContentFilterUnblockHandler::canHandleRequest): Changed to call ContentFilter::urlScheme().
+        * platform/cocoa/NetworkExtensionContentFilter.h:
+        * platform/cocoa/NetworkExtensionContentFilter.mm:
+        (replacementDataFromDecisionInfo): Added a helper to extract replacement data from the decisionInfo dictionary.
+        (WebCore::NetworkExtensionContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled.
+        (WebCore::NetworkExtensionContentFilter::create): Created a new object.
+        (WebCore::NetworkExtensionContentFilter::NetworkExtensionContentFilter): Created a NEFilterSource immediately when using the modern API.
+        (WebCore::NetworkExtensionContentFilter::responseReceived): Created a NEFilterSource when using the legacy API.
+        Called -[NEFilterSource receivedResponse:decisionHandler:] when using the modern API.
+        (WebCore::NetworkExtensionContentFilter::addData): Stopped buffering the original data.
+        (WebCore::NetworkExtensionContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&.
+        (WebCore::NetworkExtensionContentFilter::canHandleResponse): Deleted.
+        (WebCore::createNEFilterSource): Deleted.
+        (WebCore::NetworkExtensionContentFilter::getReplacementData): Deleted.
+        * platform/cocoa/ParentalControlsContentFilter.h:
+        * platform/cocoa/ParentalControlsContentFilter.mm:
+        (WebCore::ParentalControlsContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled.
+        (WebCore::ParentalControlsContentFilter::create): Created a new object.
+        (WebCore::ParentalControlsContentFilter::ParentalControlsContentFilter): Initialized m_filterState to kWFEStateBuffering.
+        (WebCore::canHandleResponse): Added a helper to check if the response can be filtered.
+        (WebCore::ParentalControlsContentFilter::responseReceived): If !canHandleResponse(), set m_filterState to kWFEStateAllowed and return.
+        Otherwise created a new WebFilterEvaluator with the response.
+        (WebCore::ParentalControlsContentFilter::addData): Called updateFilterState().
+        (WebCore::ParentalControlsContentFilter::finishedAddingData): Ditto.
+        (WebCore::ParentalControlsContentFilter::needsMoreData): Changed to check m_filterState.
+        (WebCore::ParentalControlsContentFilter::didBlockData): Ditto.
+        (WebCore::ParentalControlsContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&.
+        (WebCore::ParentalControlsContentFilter::updateFilterState): Updated m_filterState by calling -[WebFilterEvaluator filterState].
+        (WebCore::ParentalControlsContentFilter::canHandleResponse): Deleted.
+        (WebCore::ParentalControlsContentFilter::getReplacementData): Deleted.
+        * platform/spi/cocoa/NEFilterSourceSPI.h:
+        * platform/spi/cocoa/WebFilterEvaluatorSPI.h:
+        * testing/MockContentFilter.cpp:
+        (WebCore::MockContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled.
+        (WebCore::MockContentFilter::create): Created a new object.
+        (WebCore::MockContentFilter::responseReceived): Called maybeDetermineStatus().
+        (WebCore::MockContentFilter::addData): Stopped buffering the original data.
+        (WebCore::MockContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&.
+        (WebCore::MockContentFilter::unblockHandler): Asserted that we blocked data.
+        (WebCore::MockContentFilter::canHandleResponse): Deleted.
+        (WebCore::MockContentFilter::MockContentFilter): Deleted.
+        (WebCore::MockContentFilter::getReplacementData): Deleted.
+        * testing/MockContentFilter.h:
+        * testing/MockContentFilterSettings.cpp:
+        (WebCore::MockContentFilterSettings::unblockRequestURL): Changed to use a StringBuilder.
+
 2015-04-04  Chris Fleizach  <cfleiz...@apple.com>
 
         AX: Heuristic: Avoid exposing an element as clickable if mouse event delegation is handled on an AXElement with more than one descendant AXElement

Modified: trunk/Source/WebCore/loader/ContentFilter.cpp (182355 => 182356)


--- trunk/Source/WebCore/loader/ContentFilter.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/ContentFilter.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -28,12 +28,11 @@
 
 #if ENABLE(CONTENT_FILTERING)
 
-#include "DocumentLoader.h"
-#include "Frame.h"
+#include "CachedRawResource.h"
+#include "ContentFilterUnblockHandler.h"
 #include "NetworkExtensionContentFilter.h"
 #include "ParentalControlsContentFilter.h"
-#include "ScriptController.h"
-#include <bindings/ScriptValue.h>
+#include "SharedBuffer.h"
 #include <wtf/NeverDestroyed.h>
 #include <wtf/Vector.h>
 
@@ -52,107 +51,134 @@
     return types;
 }
 
-std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded(const ResourceResponse& response, DocumentLoader& documentLoader)
+std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded(DecisionFunction decisionFunction)
 {
     Container filters;
     for (auto& type : types()) {
-        if (type.canHandleResponse(response))
-            filters.append(type.create(response));
+        if (!type.enabled())
+            continue;
+
+        auto filter = type.create();
+        ASSERT(filter);
+        filters.append(WTF::move(filter));
     }
 
     if (filters.isEmpty())
         return nullptr;
 
-    return std::make_unique<ContentFilter>(WTF::move(filters), documentLoader);
+    return std::make_unique<ContentFilter>(WTF::move(filters), WTF::move(decisionFunction));
 }
 
-ContentFilter::ContentFilter(Container contentFilters, DocumentLoader& documentLoader)
+ContentFilter::ContentFilter(Container contentFilters, DecisionFunction decisionFunction)
     : m_contentFilters { WTF::move(contentFilters) }
-    , m_documentLoader { documentLoader }
+    , m_decisionFunction { WTF::move(decisionFunction) }
 {
     ASSERT(!m_contentFilters.isEmpty());
 }
 
-void ContentFilter::addData(const char* data, int length)
+ContentFilter::~ContentFilter()
 {
-    ASSERT(needsMoreData());
+    if (!m_mainResource)
+        return;
+    ASSERT(m_mainResource->hasClient(this));
+    m_mainResource->removeClient(this);
+}
 
-    for (auto& contentFilter : m_contentFilters)
-        contentFilter->addData(data, length);
+void ContentFilter::startFilteringMainResource(CachedRawResource& resource)
+{
+    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::finishedAddingData()
+
+ContentFilterUnblockHandler ContentFilter::unblockHandler() const
 {
-    ASSERT(needsMoreData());
+    ASSERT(m_state == State::Blocked);
+    ASSERT(m_blockingContentFilter);
+    ASSERT(m_blockingContentFilter->didBlockData());
+    return m_blockingContentFilter->unblockHandler();
+}
 
-    for (auto& contentFilter : m_contentFilters)
-        contentFilter->finishedAddingData();
+Ref<SharedBuffer> ContentFilter::replacementData() const
+{
+    ASSERT(m_state == State::Blocked);
+    ASSERT(m_blockingContentFilter);
+    ASSERT(m_blockingContentFilter->didBlockData());
+    return m_blockingContentFilter->replacementData();
+}
 
-    ASSERT(!needsMoreData());
+String ContentFilter::unblockRequestDeniedScript() const
+{
+    ASSERT(m_state == State::Blocked);
+    ASSERT(m_blockingContentFilter);
+    ASSERT(m_blockingContentFilter->didBlockData());
+    return m_blockingContentFilter->unblockRequestDeniedScript();
 }
 
-bool ContentFilter::needsMoreData() const
+void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse& response)
 {
-    for (auto& contentFilter : m_contentFilters) {
-        if (contentFilter->needsMoreData())
-            return true;
-    }
+    ASSERT(m_state == State::Filtering);
+    ASSERT_UNUSED(resource, resource == m_mainResource.get());
+    forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) {
+        contentFilter.responseReceived(response);
+    });
+}
 
-    return false;
+void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length)
+{
+    ASSERT(m_state == State::Filtering);
+    ASSERT_UNUSED(resource, resource == m_mainResource.get());
+    forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) {
+        contentFilter.addData(data, length);
+    });
 }
 
-bool ContentFilter::didBlockData() const
+void ContentFilter::notifyFinished(CachedResource* resource)
 {
-    for (auto& contentFilter : m_contentFilters) {
-        if (contentFilter->didBlockData())
-            return true;
-    }
-
-    return false;
+    ASSERT(m_state == State::Filtering);
+    ASSERT_UNUSED(resource, resource == m_mainResource.get());
+    forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) {
+        contentFilter.finishedAddingData();
+    });
 }
 
-const char* ContentFilter::getReplacementData(int& length) const
+void ContentFilter::forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)> function)
 {
-    ASSERT(!needsMoreData());
+    bool allFiltersAllowedLoad { true };
+    for (auto& contentFilter : m_contentFilters) {
+        if (!contentFilter->needsMoreData()) {
+            ASSERT(!contentFilter->didBlockData());
+            continue;
+        }
 
-    for (auto& contentFilter : m_contentFilters) {
-        if (contentFilter->didBlockData())
-            return contentFilter->getReplacementData(length);
+        function(*contentFilter);
+
+        if (contentFilter->didBlockData()) {
+            ASSERT(!m_blockingContentFilter);
+            m_blockingContentFilter = contentFilter.get();
+            didDecide(State::Blocked);
+            return;
+        } else if (contentFilter->needsMoreData())
+            allFiltersAllowedLoad = false;
     }
 
-    return m_contentFilters[0]->getReplacementData(length);
+    if (allFiltersAllowedLoad)
+        didDecide(State::Allowed);
 }
 
-ContentFilterUnblockHandler ContentFilter::unblockHandler() const
+void ContentFilter::didDecide(State state)
 {
-    ASSERT(didBlockData());
+    ASSERT(m_state != State::Allowed);
+    ASSERT(m_state != State::Blocked);
+    ASSERT(state == State::Allowed || state == State::Blocked);
+    m_state = state;
 
-    PlatformContentFilter* blockingFilter = nullptr;
-    for (auto& contentFilter : m_contentFilters) {
-        if (contentFilter->didBlockData()) {
-            blockingFilter = contentFilter.get();
-            break;
-        }
-    }
-    ASSERT(blockingFilter);
-
-    StringCapture unblockRequestDeniedScript { blockingFilter->unblockRequestDeniedScript() };
-    if (unblockRequestDeniedScript.string().isEmpty())
-        return blockingFilter->unblockHandler();
-
-    // It would be a layering violation for the unblock handler to access its frame,
-    // so we will execute the unblock denied script on its behalf.
-    ContentFilterUnblockHandler unblockHandler { blockingFilter->unblockHandler() };
-    RefPtr<Frame> frame { m_documentLoader.frame() };
-    return ContentFilterUnblockHandler {
-        unblockHandler.unblockURLHost(), [unblockHandler, frame, unblockRequestDeniedScript](ContentFilterUnblockHandler::DecisionHandlerFunction decisionHandler) {
-            unblockHandler.requestUnblockAsync([decisionHandler, frame, unblockRequestDeniedScript](bool unblocked) {
-                decisionHandler(unblocked);
-                if (!unblocked && frame)
-                    frame->script().executeScript(unblockRequestDeniedScript.string());
-            });
-        }
-    };
+    // Calling m_decisionFunction might delete |this|.
+    if (m_decisionFunction)
+        m_decisionFunction();
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/ContentFilter.h (182355 => 182356)


--- trunk/Source/WebCore/loader/ContentFilter.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/ContentFilter.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -28,47 +28,78 @@
 
 #if ENABLE(CONTENT_FILTERING)
 
-#include "PlatformContentFilter.h"
+#include "CachedRawResourceClient.h"
+#include "CachedResourceHandle.h"
+#include <functional>
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
-class DocumentLoader;
-class ResourceResponse;
+class CachedRawResource;
+class ContentFilterUnblockHandler;
+class PlatformContentFilter;
+class SharedBuffer;
 
-class ContentFilter final : public PlatformContentFilter {
+class ContentFilter final : private CachedRawResourceClient {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(ContentFilter);
+
 public:
     template <typename T> static void addType() { types().append(type<T>()); }
-    static std::unique_ptr<ContentFilter> createIfNeeded(const ResourceResponse&, DocumentLoader&);
 
-    void addData(const char* data, int length) override;
-    void finishedAddingData() override;
-    bool needsMoreData() const override;
-    bool didBlockData() const override;
-    const char* getReplacementData(int& length) const override;
-    ContentFilterUnblockHandler unblockHandler() const override;
+    using DecisionFunction = std::function<void()>;
+    static std::unique_ptr<ContentFilter> createIfNeeded(DecisionFunction);
+    ~ContentFilter() override;
 
+    static const char* urlScheme() { return "x-apple-content-filter"; }
+
+    void startFilteringMainResource(CachedRawResource&);
+
+    enum class State {
+        Initialized,
+        Filtering,
+        Allowed,
+        Blocked
+    };
+    State state() const { return m_state; }
+    ContentFilterUnblockHandler unblockHandler() const;
+    Ref<SharedBuffer> replacementData() const;
+    String unblockRequestDeniedScript() const;
+
 private:
     struct Type {
-        const std::function<bool(const ResourceResponse&)> canHandleResponse;
-        const std::function<std::unique_ptr<PlatformContentFilter>(const ResourceResponse&)> create;
+        const std::function<bool()> enabled;
+        const std::function<std::unique_ptr<PlatformContentFilter>()> create;
     };
     template <typename T> static Type type();
     WEBCORE_EXPORT static Vector<Type>& types();
 
     using Container = Vector<std::unique_ptr<PlatformContentFilter>>;
-    friend std::unique_ptr<ContentFilter> std::make_unique<ContentFilter>(Container&&, DocumentLoader&);
-    explicit ContentFilter(Container, DocumentLoader&);
+    friend std::unique_ptr<ContentFilter> std::make_unique<ContentFilter>(Container&&, DecisionFunction&&);
+    ContentFilter(Container, DecisionFunction);
 
-    Container m_contentFilters;
-    DocumentLoader& m_documentLoader;
+    // CachedRawResourceClient
+    void responseReceived(CachedResource*, const ResourceResponse&) override;
+    void dataReceived(CachedResource*, const char* data, int length) override;
+
+    // CachedResourceClient
+    void notifyFinished(CachedResource*) override;
+
+    void forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)>);
+    void didDecide(State);
+
+    const Container m_contentFilters;
+    const DecisionFunction m_decisionFunction;
+    CachedResourceHandle<CachedRawResource> m_mainResource;
+    PlatformContentFilter* m_blockingContentFilter { nullptr };
+    State m_state { State::Initialized };
 };
 
 template <typename T>
 ContentFilter::Type ContentFilter::type()
 {
     static_assert(std::is_base_of<PlatformContentFilter, T>::value, "Type must be a PlatformContentFilter.");
-    return { T::canHandleResponse, T::create };
+    return { T::enabled, T::create };
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (182355 => 182356)


--- trunk/Source/WebCore/loader/DocumentLoader.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -58,6 +58,7 @@
 #include "ProgressTracker.h"
 #include "ResourceHandle.h"
 #include "SchemeRegistry.h"
+#include "ScriptController.h"
 #include "SecurityPolicy.h"
 #include "Settings.h"
 #include "SubresourceLoader.h"
@@ -140,6 +141,9 @@
     , m_waitingForContentPolicy(false)
     , m_subresourceLoadersArePageCacheAcceptable(false)
     , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(*this)))
+#if ENABLE(CONTENT_FILTERING)
+    , m_contentFilter(!substituteData.isValid() ? ContentFilter::createIfNeeded(std::bind(&DocumentLoader::contentFilterDidDecide, this)) : nullptr)
+#endif
 {
 }
 
@@ -401,21 +405,6 @@
         frameLoader()->notifier().dispatchDidFinishLoading(this, identifier, finishTime);
     }
 
-#if ENABLE(CONTENT_FILTERING)
-    if (m_contentFilter && m_contentFilter->needsMoreData()) {
-        m_contentFilter->finishedAddingData();
-        int length;
-        const char* data = ""
-        if (data)
-            dataReceived(m_mainResource.get(), data, length);
-
-        if (m_contentFilter->didBlockData()) {
-            frameLoader()->client().contentFilterDidBlockLoad(m_contentFilter->unblockHandler());
-            m_contentFilter = nullptr;
-        }
-    }
-#endif
-
     maybeFinishLoadingMultipartContent();
 
     double responseEndTime = finishTime;
@@ -662,10 +651,6 @@
     }
 #endif
 
-#if ENABLE(CONTENT_FILTERING)
-    m_contentFilter = ContentFilter::createIfNeeded(response, *this);
-#endif
-
     frameLoader()->policyChecker().checkContentPolicy(m_response, [this](PolicyAction policy) {
         continueAfterContentPolicy(policy);
     });
@@ -818,14 +803,6 @@
 
         bool userChosen;
         String encoding;
-#if ENABLE(CONTENT_FILTERING)
-        // The content filter's replacement data has a known encoding that might
-        // differ from the response's encoding.
-        if (m_contentFilter && m_contentFilter->didBlockData()) {
-            ASSERT(!m_contentFilter->needsMoreData());
-            userChosen = false;
-        } else
-#endif
         if (overrideEncoding().isNull()) {
             userChosen = false;
             encoding = response().textEncodingName();
@@ -870,26 +847,6 @@
     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
 #endif
 
-#if ENABLE(CONTENT_FILTERING)
-    bool loadWasBlockedBeforeFinishing = false;
-    if (m_contentFilter && m_contentFilter->needsMoreData()) {
-        m_contentFilter->addData(data, length);
-
-        if (m_contentFilter->needsMoreData()) {
-            // Since the filter still needs more data to make a decision,
-            // avoid committing this data to prevent partial rendering of
-            // content that might later be blocked.
-            return;
-        }
-
-        data = ""
-        loadWasBlockedBeforeFinishing = m_contentFilter->didBlockData();
-
-        if (loadWasBlockedBeforeFinishing)
-            frameLoader()->client().contentFilterDidBlockLoad(m_contentFilter->unblockHandler());
-    }
-#endif
-
     if (m_identifierForLoadWithoutResourceLoader)
         frameLoader()->notifier().dispatchDidReceiveData(this, m_identifierForLoadWithoutResourceLoader, data, length, -1);
 
@@ -898,13 +855,6 @@
 
     if (!isMultipartReplacingLoad())
         commitLoad(data, length);
-
-#if ENABLE(CONTENT_FILTERING)
-    if (loadWasBlockedBeforeFinishing) {
-        cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
-        m_contentFilter = nullptr;
-    }
-#endif
 }
 
 void DocumentLoader::setupForReplace()
@@ -960,6 +910,9 @@
     stopLoading();
     if (m_mainResource && m_mainResource->hasClient(this))
         m_mainResource->removeClient(this);
+#if ENABLE(CONTENT_FILTERING)
+    m_contentFilter = nullptr;
+#endif
 
     m_applicationCacheHost->setDOMApplicationCache(nullptr);
     InspectorInstrumentation::loaderDetachedFromFrame(*m_frame, *this);
@@ -1471,7 +1424,12 @@
         frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, request);
         frameLoader()->notifier().dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, request, ResourceResponse());
     }
+
+#if ENABLE(CONTENT_FILTERING)
+    becomeMainResourceClientIfFilterAllows();
+#else
     m_mainResource->addClient(this);
+#endif
 
     // A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those.
     if (mainResourceLoader())
@@ -1507,6 +1465,9 @@
 {
     if (m_mainResource && m_mainResource->hasClient(this))
         m_mainResource->removeClient(this);
+#if ENABLE(CONTENT_FILTERING)
+    m_contentFilter = nullptr;
+#endif
 
     m_mainResource = 0;
 }
@@ -1600,4 +1561,56 @@
 }
 #endif
 
+#if ENABLE(CONTENT_FILTERING)
+void DocumentLoader::becomeMainResourceClientIfFilterAllows()
+{
+    ASSERT(m_mainResource);
+    if (m_contentFilter) {
+        ASSERT(m_contentFilter->state() == ContentFilter::State::Initialized);
+        m_contentFilter->startFilteringMainResource(*m_mainResource);
+    } else
+        m_mainResource->addClient(this);
+}
+
+void DocumentLoader::installContentFilterUnblockHandler(ContentFilter& contentFilter)
+{
+    ContentFilterUnblockHandler unblockHandler { contentFilter.unblockHandler() };
+    unblockHandler.setUnreachableURL(documentURL());
+    RefPtr<Frame> frame { this->frame() };
+    String unblockRequestDeniedScript { contentFilter.unblockRequestDeniedScript() };
+    if (!unblockRequestDeniedScript.isEmpty() && frame) {
+        static_assert(std::is_base_of<ThreadSafeRefCounted<Frame>, Frame>::value, "Frame must be ThreadSafeRefCounted.");
+        StringCapture capturedScript { unblockRequestDeniedScript };
+        unblockHandler.wrapWithDecisionHandler([frame, capturedScript](bool unblocked) {
+            if (!unblocked)
+                frame->script().executeScript(capturedScript.string());
+        });
+    }
+    frameLoader()->client().contentFilterDidBlockLoad(WTF::move(unblockHandler));
+}
+
+void DocumentLoader::contentFilterDidDecide()
+{
+    using State = ContentFilter::State;
+    ASSERT(m_contentFilter);
+    ASSERT(m_contentFilter->state() == State::Blocked || m_contentFilter->state() == State::Allowed);
+    std::unique_ptr<ContentFilter> contentFilter;
+    std::swap(contentFilter, m_contentFilter);
+    if (contentFilter->state() == State::Allowed) {
+        if (m_mainResource)
+            m_mainResource->addClient(this);
+        return;
+    }
+
+    installContentFilterUnblockHandler(*contentFilter);
+
+    URL blockedURL;
+    blockedURL.setProtocol(ContentFilter::urlScheme());
+    blockedURL.setHost(ASCIILiteral("blocked-page"));
+    SubstituteData substituteData { contentFilter->replacementData(), ASCIILiteral("text/html"), ASCIILiteral("UTF-8"), documentURL() };
+    frame()->navigationScheduler().scheduleSubstituteDataLoad(blockedURL, substituteData);
+}
+#endif
+
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/DocumentLoader.h (182355 => 182356)


--- trunk/Source/WebCore/loader/DocumentLoader.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/DocumentLoader.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -64,7 +64,6 @@
     class ArchiveResourceCollection;
     class CachedRawResource;
     class CachedResourceLoader;
-    class ContentFilter;
     class FormState;
     class Frame;
     class FrameLoader;
@@ -73,6 +72,10 @@
     class SharedBuffer;
     class SubstituteResource;
 
+#if ENABLE(CONTENT_FILTERING)
+    class ContentFilter;
+#endif
+
     typedef HashMap<unsigned long, RefPtr<ResourceLoader>> ResourceLoaderMap;
     typedef Vector<ResourceResponse> ResponseVector;
 
@@ -330,6 +333,12 @@
 
         void clearMainResource();
 
+#if ENABLE(CONTENT_FILTERING)
+        void becomeMainResourceClientIfFilterAllows();
+        void installContentFilterUnblockHandler(ContentFilter&);
+        void contentFilterDidDecide();
+#endif
+
         Frame* m_frame;
         Ref<CachedResourceLoader> m_cachedResourceLoader;
 

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (182355 => 182356)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -1124,7 +1124,6 @@
 
 void FrameLoader::prepareForLoadStart()
 {
-    policyChecker().prepareForLoadStart();
     m_progressTracker->progressStarted();
     m_client.dispatchDidStartProvisionalLoad();
 

Modified: trunk/Source/WebCore/loader/NavigationScheduler.cpp (182355 => 182356)


--- trunk/Source/WebCore/loader/NavigationScheduler.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/NavigationScheduler.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -278,6 +278,26 @@
     bool m_haveToldClient;
 };
 
+class ScheduledSubstituteDataLoad : public ScheduledNavigation {
+public:
+    ScheduledSubstituteDataLoad(const URL& baseURL, const SubstituteData& substituteData)
+        : ScheduledNavigation { 0, LockHistory::No, LockBackForwardList::No, false, false }
+        , m_baseURL { baseURL }
+        , m_substituteData { substituteData }
+    {
+    }
+
+    void fire(Frame& frame) override
+    {
+        UserGestureIndicator gestureIndicator { wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture };
+        frame.loader().load(FrameLoadRequest { &frame, m_baseURL, m_substituteData });
+    }
+
+private:
+    URL m_baseURL;
+    SubstituteData m_substituteData;
+};
+
 NavigationScheduler::NavigationScheduler(Frame& frame)
     : m_frame(frame)
     , m_timer(*this, &NavigationScheduler::timerFired)
@@ -430,6 +450,12 @@
     schedule(std::make_unique<ScheduledHistoryNavigation>(steps));
 }
 
+void NavigationScheduler::scheduleSubstituteDataLoad(const URL& baseURL, const SubstituteData& substituteData)
+{
+    if (shouldScheduleNavigation())
+        schedule(std::make_unique<ScheduledSubstituteDataLoad>(baseURL, substituteData));
+}
+
 void NavigationScheduler::timerFired()
 {
     if (!m_frame.page())

Modified: trunk/Source/WebCore/loader/NavigationScheduler.h (182355 => 182356)


--- trunk/Source/WebCore/loader/NavigationScheduler.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/NavigationScheduler.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -41,6 +41,7 @@
 class Frame;
 class ScheduledNavigation;
 class SecurityOrigin;
+class SubstituteData;
 class URL;
 
 class NavigationDisablerForBeforeUnload {
@@ -73,6 +74,7 @@
     void scheduleFormSubmission(PassRefPtr<FormSubmission>);
     void scheduleRefresh();
     void scheduleHistoryNavigation(int steps);
+    void scheduleSubstituteDataLoad(const URL& baseURL, const SubstituteData&);
 
     void startTimer();
 

Modified: trunk/Source/WebCore/loader/PolicyChecker.cpp (182355 => 182356)


--- trunk/Source/WebCore/loader/PolicyChecker.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/PolicyChecker.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -56,13 +56,6 @@
 {
 }
 
-void PolicyChecker::prepareForLoadStart()
-{
-#if ENABLE(CONTENT_FILTERING)
-    m_contentFilterUnblockHandler = { };
-#endif
-}
-
 void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function)
 {
     checkNavigationPolicy(newRequest, m_frame.loader().activeDocumentLoader(), nullptr, WTF::move(function));
@@ -120,7 +113,9 @@
                 frame->loader().reload();
         });
         continueAfterNavigationPolicy(PolicyIgnore);
+        return;
     }
+    m_contentFilterUnblockHandler = { };
 #endif
 
     m_delegateIsDecidingNavigationPolicy = true;

Modified: trunk/Source/WebCore/loader/PolicyChecker.h (182355 => 182356)


--- trunk/Source/WebCore/loader/PolicyChecker.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/loader/PolicyChecker.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -54,7 +54,6 @@
 public:
     explicit PolicyChecker(Frame&);
 
-    void prepareForLoadStart();
     void checkNavigationPolicy(const ResourceRequest&, DocumentLoader*, PassRefPtr<FormState>, NavigationPolicyDecisionFunction);
     void checkNavigationPolicy(const ResourceRequest&, NavigationPolicyDecisionFunction);
     void checkNewWindowPolicy(const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, NewWindowPolicyDecisionFunction);

Modified: trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h (182355 => 182356)


--- trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -28,6 +28,7 @@
 
 #if ENABLE(CONTENT_FILTERING)
 
+#include "URL.h"
 #include <functional>
 #include <wtf/RetainPtr.h>
 #include <wtf/text/WTFString.h>
@@ -47,8 +48,6 @@
     using DecisionHandlerFunction = std::function<void(bool unblocked)>;
     using UnblockRequesterFunction = std::function<void(DecisionHandlerFunction)>;
 
-    static const char* unblockURLScheme() { return "x-apple-content-filter"; }
-
     ContentFilterUnblockHandler() = default;
     WEBCORE_EXPORT ContentFilterUnblockHandler(String unblockURLHost, UnblockRequesterFunction);
 #if PLATFORM(IOS)
@@ -60,11 +59,15 @@
     WEBCORE_EXPORT static bool decode(NSCoder *, ContentFilterUnblockHandler&);
     WEBCORE_EXPORT bool canHandleRequest(const ResourceRequest&) const;
     WEBCORE_EXPORT void requestUnblockAsync(DecisionHandlerFunction) const;
+    void wrapWithDecisionHandler(const DecisionHandlerFunction&);
 
     const String& unblockURLHost() const { return m_unblockURLHost; }
+    const URL& unreachableURL() const { return m_unreachableURL; }
+    void setUnreachableURL(const URL& url) { m_unreachableURL = url; }
 
 private:
     String m_unblockURLHost;
+    URL m_unreachableURL;
     UnblockRequesterFunction m_unblockRequester;
 #if PLATFORM(IOS)
     RetainPtr<WebFilterEvaluator> m_webFilterEvaluator;

Modified: trunk/Source/WebCore/platform/PlatformContentFilter.h (182355 => 182356)


--- trunk/Source/WebCore/platform/PlatformContentFilter.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/PlatformContentFilter.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -26,12 +26,14 @@
 #ifndef PlatformContentFilter_h
 #define PlatformContentFilter_h
 
-#include "ContentFilterUnblockHandler.h"
+#include <wtf/Ref.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
+class ContentFilterUnblockHandler;
 class ResourceResponse;
+class SharedBuffer;
 
 class PlatformContentFilter {
     WTF_MAKE_FAST_ALLOCATED;
@@ -42,11 +44,12 @@
 
 public:
     virtual ~PlatformContentFilter() { }
+    virtual void responseReceived(const ResourceResponse&) = 0;
     virtual void addData(const char* data, int length) = 0;
     virtual void finishedAddingData() = 0;
     virtual bool needsMoreData() const = 0;
     virtual bool didBlockData() const = 0;
-    virtual const char* getReplacementData(int& length) const = 0;
+    virtual Ref<SharedBuffer> replacementData() const = 0;
     virtual ContentFilterUnblockHandler unblockHandler() const = 0;
     virtual String unblockRequestDeniedScript() const { return emptyString(); }
 };

Modified: trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm (182355 => 182356)


--- trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm	2015-04-05 07:52:14 UTC (rev 182356)
@@ -29,6 +29,7 @@
 #if ENABLE(CONTENT_FILTERING)
 
 #import "BlockExceptions.h"
+#import "ContentFilter.h"
 #import "ResourceRequest.h"
 
 #if PLATFORM(IOS)
@@ -43,6 +44,7 @@
 #endif
 
 static NSString * const unblockURLHostKey { @"unblockURLHost" };
+static NSString * const unreachableURLKey { @"unreachableURL" };
 
 namespace WebCore {
 
@@ -60,6 +62,21 @@
 }
 #endif
 
+void ContentFilterUnblockHandler::wrapWithDecisionHandler(const DecisionHandlerFunction& decisionHandler)
+{
+    ContentFilterUnblockHandler wrapped { *this };
+    UnblockRequesterFunction wrappedRequester { [wrapped, decisionHandler](DecisionHandlerFunction wrappedDecisionHandler) {
+        wrapped.requestUnblockAsync([wrappedDecisionHandler, decisionHandler](bool unblocked) {
+            wrappedDecisionHandler(unblocked);
+            decisionHandler(unblocked);
+        });
+    }};
+#if PLATFORM(IOS)
+    m_webFilterEvaluator = nullptr;
+#endif
+    std::swap(m_unblockRequester, wrappedRequester);
+}
+
 bool ContentFilterUnblockHandler::needsUIProcess() const
 {
 #if PLATFORM(IOS)
@@ -74,6 +91,7 @@
     ASSERT_ARG(coder, coder.allowsKeyedCoding && coder.requiresSecureCoding);
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
     [coder encodeObject:m_unblockURLHost forKey:unblockURLHostKey];
+    [coder encodeObject:(NSURL *)m_unreachableURL forKey:unreachableURLKey];
 #if PLATFORM(IOS)
     [coder encodeObject:m_webFilterEvaluator.get() forKey:webFilterEvaluatorKey];
 #endif
@@ -85,6 +103,7 @@
     ASSERT_ARG(coder, coder.allowsKeyedCoding && coder.requiresSecureCoding);
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
     unblockHandler.m_unblockURLHost = [coder decodeObjectOfClass:[NSString class] forKey:unblockURLHostKey];
+    unblockHandler.m_unreachableURL = [coder decodeObjectOfClass:[NSURL class] forKey:unreachableURLKey];
 #if PLATFORM(IOS)
     unblockHandler.m_webFilterEvaluator = [coder decodeObjectOfClass:getWebFilterEvaluatorClass() forKey:webFilterEvaluatorKey];
 #endif
@@ -104,7 +123,7 @@
 #endif
     }
 
-    return request.url().protocolIs(unblockURLScheme()) && equalIgnoringCase(request.url().host(), m_unblockURLHost);
+    return request.url().protocolIs(ContentFilter::urlScheme()) && equalIgnoringCase(request.url().host(), m_unblockURLHost);
 }
 
 static inline void dispatchToMainThread(void (^block)())

Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h (182355 => 182356)


--- trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -27,11 +27,9 @@
 #define NetworkExtensionContentFilter_h
 
 #include "PlatformContentFilter.h"
-#include "SharedBuffer.h"
 #include <objc/NSObjCRuntime.h>
 #include <wtf/Compiler.h>
 #include <wtf/OSObjectPtr.h>
-#include <wtf/Ref.h>
 #include <wtf/RetainPtr.h>
 
 #define HAVE_NETWORK_EXTENSION PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 && CPU(X86_64))
@@ -42,31 +40,31 @@
 OBJC_CLASS NSData;
 OBJC_CLASS NSDictionary;
 OBJC_CLASS NSMutableData;
-
+OBJC_CLASS NSString;
 namespace WebCore {
 
 class NetworkExtensionContentFilter final : public PlatformContentFilter {
-    friend std::unique_ptr<NetworkExtensionContentFilter> std::make_unique<NetworkExtensionContentFilter>(const ResourceResponse&);
+    friend std::unique_ptr<NetworkExtensionContentFilter> std::make_unique<NetworkExtensionContentFilter>();
 
 public:
-    static bool canHandleResponse(const ResourceResponse&);
-    static std::unique_ptr<NetworkExtensionContentFilter> create(const ResourceResponse&);
+    static bool enabled();
+    static std::unique_ptr<NetworkExtensionContentFilter> create();
 
+    void responseReceived(const ResourceResponse&) override;
     void addData(const char* data, int length) override;
     void finishedAddingData() override;
     bool needsMoreData() const override;
     bool didBlockData() const override;
-    const char* getReplacementData(int& length) const override;
+    Ref<SharedBuffer> replacementData() const override;
     ContentFilterUnblockHandler unblockHandler() const override;
 
 private:
-    explicit NetworkExtensionContentFilter(const ResourceResponse&);
+    NetworkExtensionContentFilter();
     void handleDecision(NEFilterSourceStatus, NSData *replacementData);
 
     NEFilterSourceStatus m_status;
     OSObjectPtr<dispatch_queue_t> m_queue;
     OSObjectPtr<dispatch_semaphore_t> m_semaphore;
-    Ref<SharedBuffer> m_originalData;
     RetainPtr<NSData> m_replacementData;
     RetainPtr<NEFilterSource> m_neFilterSource;
 };

Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm (182355 => 182356)


--- trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm	2015-04-05 07:52:14 UTC (rev 182356)
@@ -28,21 +28,21 @@
 
 #if HAVE(NETWORK_EXTENSION)
 
+#import "ContentFilterUnblockHandler.h"
 #import "NEFilterSourceSPI.h"
 #import "ResourceResponse.h"
+#import "SharedBuffer.h"
 #import "SoftLinking.h"
+#import "URL.h"
 #import <objc/runtime.h>
 
 SOFT_LINK_FRAMEWORK(NetworkExtension);
 SOFT_LINK_CLASS(NetworkExtension, NEFilterSource);
 
 #if HAVE(MODERN_NE_FILTER_SOURCE)
-// FIXME: <rdar://problem/20165664> Expose decisionHandler dictionary keys as NSString constants in NEFilterSource.h
-static NSString * const optionsPageData = @"PageData";
-
 static inline NSData *replacementDataFromDecisionInfo(NSDictionary *decisionInfo)
 {
-    id replacementData = decisionInfo[optionsPageData];
+    id replacementData = decisionInfo[NEFilterSourceOptionsPageData];
     ASSERT(!replacementData || [replacementData isKindOfClass:[NSData class]]);
     return replacementData;
 }
@@ -50,37 +50,38 @@
 
 namespace WebCore {
 
-bool NetworkExtensionContentFilter::canHandleResponse(const ResourceResponse& response)
+bool NetworkExtensionContentFilter::enabled()
 {
-    return response.url().protocolIsInHTTPFamily() && [getNEFilterSourceClass() filterRequired];
+    return [getNEFilterSourceClass() filterRequired];
 }
 
-std::unique_ptr<NetworkExtensionContentFilter> NetworkExtensionContentFilter::create(const ResourceResponse& response)
+std::unique_ptr<NetworkExtensionContentFilter> NetworkExtensionContentFilter::create()
 {
-    return std::make_unique<NetworkExtensionContentFilter>(response);
+    return std::make_unique<NetworkExtensionContentFilter>();
 }
 
-static inline RetainPtr<NEFilterSource> createNEFilterSource(const URL& url, dispatch_queue_t decisionQueue)
-{
-#if HAVE(MODERN_NE_FILTER_SOURCE)
-    UNUSED_PARAM(url);
-    return adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:decisionQueue]);
-#else
-    UNUSED_PARAM(decisionQueue);
-    return adoptNS([allocNEFilterSourceInstance() initWithURL:url direction:NEFilterSourceDirectionInbound socketIdentifier:0]);
-#endif
-}
-
-NetworkExtensionContentFilter::NetworkExtensionContentFilter(const ResourceResponse& response)
+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)) }
-    , m_originalData { *SharedBuffer::create() }
-    , m_neFilterSource { createNEFilterSource(response.url(), m_queue.get()) }
+#if HAVE(MODERN_NE_FILTER_SOURCE)
+    , m_neFilterSource { adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:m_queue.get()]) }
+#endif
 {
     ASSERT([getNEFilterSourceClass() filterRequired]);
+}
 
-#if HAVE(MODERN_NE_FILTER_SOURCE)
+void NetworkExtensionContentFilter::responseReceived(const ResourceResponse& response)
+{
+    if (!response.url().protocolIsInHTTPFamily()) {
+        m_status = NEFilterSourceStatusPass;
+        return;
+    }
+
+#if !HAVE(MODERN_NE_FILTER_SOURCE)
+    ASSERT(!m_neFilterSource);
+    m_neFilterSource = adoptNS([allocNEFilterSourceInstance() initWithURL:response.url() direction:NEFilterSourceDirectionInbound socketIdentifier:0]);
+#else
     [m_neFilterSource receivedResponse:response.nsURLResponse() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
         handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
     }];
@@ -96,12 +97,6 @@
 {
     RetainPtr<NSData> copiedData { [NSData dataWithBytes:(void*)data length:length] };
 
-    // FIXME: NEFilterSource doesn't buffer data like WebFilterEvaluator does,
-    // so we need to do it ourselves so getReplacementData() can return the
-    // original bytes back to the loader. We should find a way to remove this
-    // additional copy.
-    m_originalData->append((CFDataRef)copiedData.get());
-
 #if HAVE(MODERN_NE_FILTER_SOURCE)
     [m_neFilterSource receivedData:copiedData.get() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
         handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
@@ -148,15 +143,10 @@
     return m_status == NEFilterSourceStatusBlock;
 }
 
-const char* NetworkExtensionContentFilter::getReplacementData(int& length) const
+Ref<SharedBuffer> NetworkExtensionContentFilter::replacementData() const
 {
-    if (didBlockData()) {
-        length = [m_replacementData length];
-        return static_cast<const char*>([m_replacementData bytes]);
-    }
-
-    length = m_originalData->size();
-    return m_originalData->data();
+    ASSERT(didBlockData());
+    return adoptRef(*SharedBuffer::wrapNSData(m_replacementData.get()).leakRef());
 }
 
 ContentFilterUnblockHandler NetworkExtensionContentFilter::unblockHandler() const

Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h (182355 => 182356)


--- trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -36,22 +36,25 @@
 namespace WebCore {
 
 class ParentalControlsContentFilter final : public PlatformContentFilter {
-    friend std::unique_ptr<ParentalControlsContentFilter> std::make_unique<ParentalControlsContentFilter>(const ResourceResponse&);
+    friend std::unique_ptr<ParentalControlsContentFilter> std::make_unique<ParentalControlsContentFilter>();
 
 public:
-    static bool canHandleResponse(const ResourceResponse&);
-    static std::unique_ptr<ParentalControlsContentFilter> create(const ResourceResponse&);
+    static bool enabled();
+    static std::unique_ptr<ParentalControlsContentFilter> create();
 
+    void responseReceived(const ResourceResponse&) override;
     void addData(const char* data, int length) override;
     void finishedAddingData() override;
     bool needsMoreData() const override;
     bool didBlockData() const override;
-    const char* getReplacementData(int& length) const override;
+    Ref<SharedBuffer> replacementData() const override;
     ContentFilterUnblockHandler unblockHandler() const override;
 
 private:
-    explicit ParentalControlsContentFilter(const ResourceResponse&);
+    ParentalControlsContentFilter();
+    void updateFilterState();
 
+    OSStatus m_filterState;
     RetainPtr<WebFilterEvaluator> m_webFilterEvaluator;
     RetainPtr<NSData> m_replacementData;
 };

Modified: trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm (182355 => 182356)


--- trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm	2015-04-05 07:52:14 UTC (rev 182356)
@@ -26,7 +26,9 @@
 #import "config.h"
 #import "ParentalControlsContentFilter.h"
 
+#import "ContentFilterUnblockHandler.h"
 #import "ResourceResponse.h"
+#import "SharedBuffer.h"
 #import "SoftLinking.h"
 #import "WebFilterEvaluatorSPI.h"
 #import <objc/runtime.h>
@@ -36,36 +38,49 @@
 
 namespace WebCore {
 
-bool ParentalControlsContentFilter::canHandleResponse(const ResourceResponse& response)
+bool ParentalControlsContentFilter::enabled()
 {
-    if (!response.url().protocolIsInHTTPFamily())
-        return false;
+    return [getWebFilterEvaluatorClass() isManagedSession];
+}
 
-    if ([getWebFilterEvaluatorClass() isManagedSession]) {
-#if PLATFORM(MAC)
-        if (response.url().protocolIs("https"))
-#endif
-            return true;
-    }
+std::unique_ptr<ParentalControlsContentFilter> ParentalControlsContentFilter::create()
+{
+    return std::make_unique<ParentalControlsContentFilter>();
+}
 
-    return false;
+ParentalControlsContentFilter::ParentalControlsContentFilter()
+    : m_filterState { kWFEStateBuffering }
+{
+    ASSERT([getWebFilterEvaluatorClass() isManagedSession]);
 }
 
-std::unique_ptr<ParentalControlsContentFilter> ParentalControlsContentFilter::create(const ResourceResponse& response)
+static inline bool canHandleResponse(const ResourceResponse& response)
 {
-    return std::make_unique<ParentalControlsContentFilter>(response);
+#if PLATFORM(MAC)
+    return response.url().protocolIs("https");
+#else
+    return response.url().protocolIsInHTTPFamily();
+#endif
 }
 
-ParentalControlsContentFilter::ParentalControlsContentFilter(const ResourceResponse& response)
-    : m_webFilterEvaluator { adoptNS([allocWebFilterEvaluatorInstance() initWithResponse:response.nsURLResponse()]) }
+void ParentalControlsContentFilter::responseReceived(const ResourceResponse& response)
 {
-    ASSERT([getWebFilterEvaluatorClass() isManagedSession]);
+    ASSERT(!m_webFilterEvaluator);
+
+    if (!canHandleResponse(response)) {
+        m_filterState = kWFEStateAllowed;
+        return;
+    }
+
+    m_webFilterEvaluator = adoptNS([allocWebFilterEvaluatorInstance() initWithResponse:response.nsURLResponse()]);
+    updateFilterState();
 }
 
 void ParentalControlsContentFilter::addData(const char* data, int length)
 {
     ASSERT(![m_replacementData.get() length]);
     m_replacementData = [m_webFilterEvaluator addData:[NSData dataWithBytesNoCopy:(void*)data length:length freeWhenDone:NO]];
+    updateFilterState();
     ASSERT(needsMoreData() || [m_replacementData.get() length]);
 }
 
@@ -73,22 +88,23 @@
 {
     ASSERT(![m_replacementData.get() length]);
     m_replacementData = [m_webFilterEvaluator dataComplete];
+    updateFilterState();
 }
 
 bool ParentalControlsContentFilter::needsMoreData() const
 {
-    return [m_webFilterEvaluator filterState] == kWFEStateBuffering;
+    return m_filterState == kWFEStateBuffering;
 }
 
 bool ParentalControlsContentFilter::didBlockData() const
 {
-    return [m_webFilterEvaluator wasBlocked];
+    return m_filterState == kWFEStateBlocked;
 }
 
-const char* ParentalControlsContentFilter::getReplacementData(int& length) const
+Ref<SharedBuffer> ParentalControlsContentFilter::replacementData() const
 {
-    length = [m_replacementData length];
-    return static_cast<const char*>([m_replacementData bytes]);
+    ASSERT(didBlockData());
+    return adoptRef(*SharedBuffer::wrapNSData(m_replacementData.get()).leakRef());
 }
 
 ContentFilterUnblockHandler ParentalControlsContentFilter::unblockHandler() const
@@ -100,4 +116,9 @@
 #endif
 }
 
+void ParentalControlsContentFilter::updateFilterState()
+{
+    m_filterState = [m_webFilterEvaluator filterState];
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h (182355 => 182356)


--- trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -68,6 +68,7 @@
 - (void)finishedLoadingWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
 - (void)remediateWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
 @end
+
 #endif
 
 #endif

Modified: trunk/Source/WebCore/platform/spi/cocoa/WebFilterEvaluatorSPI.h (182355 => 182356)


--- trunk/Source/WebCore/platform/spi/cocoa/WebFilterEvaluatorSPI.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/platform/spi/cocoa/WebFilterEvaluatorSPI.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -32,7 +32,10 @@
 #import <TargetConditionals.h>
 
 enum {
-    kWFEStateBuffering = 2
+    kWFEStateAllowed = 0,
+    kWFEStateBlocked = 1,
+    kWFEStateBuffering = 2,
+    kWFEStateEvaluating = 3
 };
 
 @interface WebFilterEvaluator : NSObject

Modified: trunk/Source/WebCore/testing/MockContentFilter.cpp (182355 => 182356)


--- trunk/Source/WebCore/testing/MockContentFilter.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/testing/MockContentFilter.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -29,8 +29,11 @@
 #if ENABLE(CONTENT_FILTERING)
 
 #include "ContentFilter.h"
+#include "ContentFilterUnblockHandler.h"
+#include "SharedBuffer.h"
 #include <mutex>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
@@ -50,24 +53,23 @@
     return MockContentFilterSettings::singleton();
 }
 
-bool MockContentFilter::canHandleResponse(const ResourceResponse&)
+bool MockContentFilter::enabled()
 {
     return settings().enabled();
 }
 
-std::unique_ptr<MockContentFilter> MockContentFilter::create(const ResourceResponse& response)
+std::unique_ptr<MockContentFilter> MockContentFilter::create()
 {
-    return std::make_unique<MockContentFilter>(response);
+    return std::make_unique<MockContentFilter>();
 }
 
-MockContentFilter::MockContentFilter(const ResourceResponse&)
+void MockContentFilter::responseReceived(const ResourceResponse&)
 {
     maybeDetermineStatus(DecisionPoint::AfterResponse);
 }
 
-void MockContentFilter::addData(const char* data, int length)
+void MockContentFilter::addData(const char*, int)
 {
-    m_replacementData.append(data, length);
     maybeDetermineStatus(DecisionPoint::AfterAddData);
 }
 
@@ -86,14 +88,15 @@
     return m_status == Status::Blocked;
 }
 
-const char* MockContentFilter::getReplacementData(int& length) const
+Ref<SharedBuffer> MockContentFilter::replacementData() const
 {
-    length = m_replacementData.size();
-    return m_replacementData.data();
+    ASSERT(didBlockData());
+    return adoptRef(*SharedBuffer::create(m_replacementData.data(), m_replacementData.size()).leakRef());
 }
 
 ContentFilterUnblockHandler MockContentFilter::unblockHandler() const
 {
+    ASSERT(didBlockData());
     using DecisionHandlerFunction = ContentFilterUnblockHandler::DecisionHandlerFunction;
 
     return ContentFilterUnblockHandler {

Modified: trunk/Source/WebCore/testing/MockContentFilter.h (182355 => 182356)


--- trunk/Source/WebCore/testing/MockContentFilter.h	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/testing/MockContentFilter.h	2015-04-05 07:52:14 UTC (rev 182356)
@@ -32,18 +32,19 @@
 namespace WebCore {
 
 class MockContentFilter final : public PlatformContentFilter {
-    friend std::unique_ptr<MockContentFilter> std::make_unique<MockContentFilter>(const ResourceResponse&);
+    friend std::unique_ptr<MockContentFilter> std::make_unique<MockContentFilter>();
 
 public:
     static void ensureInstalled();
-    static bool canHandleResponse(const ResourceResponse&);
-    static std::unique_ptr<MockContentFilter> create(const ResourceResponse&);
+    static bool enabled();
+    static std::unique_ptr<MockContentFilter> create();
 
+    void responseReceived(const ResourceResponse&) override;
     void addData(const char* data, int length) override;
     void finishedAddingData() override;
     bool needsMoreData() const override;
     bool didBlockData() const override;
-    const char* getReplacementData(int& length) const override;
+    Ref<SharedBuffer> replacementData() const override;
     ContentFilterUnblockHandler unblockHandler() const override;
     String unblockRequestDeniedScript() const override;
 
@@ -54,7 +55,7 @@
         Blocked
     };
 
-    explicit MockContentFilter(const ResourceResponse&);
+    MockContentFilter() = default;
     void maybeDetermineStatus(MockContentFilterSettings::DecisionPoint);
 
     Vector<char> m_replacementData;

Modified: trunk/Source/WebCore/testing/MockContentFilterSettings.cpp (182355 => 182356)


--- trunk/Source/WebCore/testing/MockContentFilterSettings.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebCore/testing/MockContentFilterSettings.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -28,9 +28,11 @@
 
 #if ENABLE(CONTENT_FILTERING)
 
+#include "ContentFilter.h"
 #include "ContentFilterUnblockHandler.h"
 #include <mutex>
 #include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
@@ -50,9 +52,11 @@
     static LazyNeverDestroyed<String> unblockRequestURL;
     static std::once_flag onceFlag;
     std::call_once(onceFlag, [] {
-        unblockRequestURL.construct(ContentFilterUnblockHandler::unblockURLScheme());
-        unblockRequestURL.get().append("://");
-        unblockRequestURL.get().append(unblockURLHost());
+        StringBuilder unblockRequestURLBuilder;
+        unblockRequestURLBuilder.append(ContentFilter::urlScheme());
+        unblockRequestURLBuilder.append("://");
+        unblockRequestURLBuilder.append(unblockURLHost());
+        unblockRequestURL.construct(unblockRequestURLBuilder.toString());
     });
     return unblockRequestURL;
 }

Modified: trunk/Source/WebKit2/ChangeLog (182355 => 182356)


--- trunk/Source/WebKit2/ChangeLog	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebKit2/ChangeLog	2015-04-05 07:52:14 UTC (rev 182356)
@@ -1,3 +1,14 @@
+2015-04-04  Andy Estes  <aes...@apple.com>
+
+        [Content Filtering] Blocked page is not always displayed when it should be
+        https://bugs.webkit.org/show_bug.cgi?id=143410
+
+        Reviewed by Andreas Kling.
+
+        * UIProcess/WebFrameProxy.cpp:
+        (WebKit::WebFrameProxy::didStartProvisionalLoad): Stopped clearing m_contentFilterUnblockHandler here.
+        (WebKit::WebFrameProxy::didHandleContentFilterUnblockNavigation): Started doing it here instead.
+
 2015-04-04  Chris Dumez  <cdu...@apple.com>
 
         [WK2][Cocoa] Add a way to temporarily disable the WebKit Network Cache for testing

Modified: trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp (182355 => 182356)


--- trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp	2015-04-05 06:51:15 UTC (rev 182355)
+++ trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp	2015-04-05 07:52:14 UTC (rev 182356)
@@ -127,9 +127,6 @@
 void WebFrameProxy::didStartProvisionalLoad(const String& url)
 {
     m_frameLoadState.didStartProvisionalLoad(url);
-#if ENABLE(CONTENT_FILTERING)
-    m_contentFilterUnblockHandler = { };
-#endif
 }
 
 void WebFrameProxy::didReceiveServerRedirectForProvisionalLoad(const String& url)
@@ -236,8 +233,10 @@
 #if ENABLE(CONTENT_FILTERING)
 bool WebFrameProxy::didHandleContentFilterUnblockNavigation(const WebCore::ResourceRequest& request)
 {
-    if (!m_contentFilterUnblockHandler.canHandleRequest(request))
+    if (!m_contentFilterUnblockHandler.canHandleRequest(request)) {
+        m_contentFilterUnblockHandler = { };
         return false;
+    }
 
     RefPtr<WebPageProxy> page { m_page };
     ASSERT(page);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to