Changeset 182356 in webkit
- Timestamp:
- Apr 5, 2015 12:52:14 AM (9 years ago)
- Location:
- trunk
- Files:
-
- 28 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r182355 r182356 1 2015-04-04 Andy Estes <aestes@apple.com> 2 3 [Content Filtering] Blocked page is not always displayed when it should be 4 https://bugs.webkit.org/show_bug.cgi?id=143410 5 6 Reviewed by Andreas Kling. 7 8 * TestExpectations: Unskipped block-after-add-data.html. 9 * contentfiltering/block-after-add-data-expected.html: Added a passing expectation. 10 * contentfiltering/block-after-response-expected.html: Ditto. 11 1 12 2015-04-04 Chris Fleizach <cfleizach@apple.com> 2 13 -
trunk/LayoutTests/TestExpectations
r182339 r182356 498 498 webkit.org/b/114280 svg/animations/smil-leak-elements.svg [ Pass Failure ] 499 499 500 # contentfiltering/block-after-add-data.html times out unexpectedly501 webkit.org/b/142894 contentfiltering/block-after-add-data.html [ Skip ]502 503 500 webkit.org/b/143085 media/track/track-mode.html [ Pass Timeout ] 504 501 -
trunk/LayoutTests/contentfiltering/block-after-add-data-expected.html
r181877 r182356 1 1 <!DOCTYPE html> 2 <iframe src="data:text/html,<!DOCTYPE html><body> "></iframe>2 <iframe src="data:text/html,<!DOCTYPE html><body>PASS"></iframe> -
trunk/LayoutTests/contentfiltering/block-after-response-expected.html
r181877 r182356 1 1 <!DOCTYPE html> 2 <iframe src="data:text/html,<!DOCTYPE html><body> FAIL"></iframe>2 <iframe src="data:text/html,<!DOCTYPE html><body>PASS"></iframe> -
trunk/Source/WebCore/ChangeLog
r182355 r182356 1 2015-04-04 Andy Estes <aestes@apple.com> 2 3 [Content Filtering] Blocked page is not always displayed when it should be 4 https://bugs.webkit.org/show_bug.cgi?id=143410 5 rdar://problem/20211099 6 7 Reviewed by Andreas Kling. 8 9 These tests now pass: contentfiltering/block-after-add-data.html 10 contentfiltering/block-after-response.html 11 12 There were several problems with how ContentFilter loaded replacement data: 13 (1) Replacement data was delivered to DocumentLoader as if it were the original document's data. This assumes 14 that the original data was a UTF-8 encoded HTML document, which is not always true. We had a way to reset 15 the encoding, but not the content type. 16 (2) Replacement data was never delivered when the filter blocks in DocumentLoader::responseReceived(). 17 (3) The main resource load was cancelled before the replacement data could be rendered when the filter blocks 18 in DocumentLoader::dataReceived(). 19 The result was that only when the load was blocked after DocumentLoader::notifyFinished() would the replacement 20 data be shown properly, and only when problem (1) wasn't occurring. 21 22 This patch addresses these issues by using the substitute data mechanism to deliver replacement data. By using 23 substitute data, we can ensure that the original load is cancelled at the earliest opportunity and that the 24 replacement data is loaded with the proper content type and encoding. 25 26 Accomplishing this required changing the way ContentFilter interacts with DocumentLoader. Instead of placing 27 ContentFilter hooks throughout DocumentLoader, this patch makes ContentFilter itself the client of the 28 CachedRawResource for the duration of the filtering. If the filter decides to allow the load, DocumentLoader 29 adds itself as a client causing CachedRawResource to deliver to it the response and buffered data. If the 30 filter decides to block the load, DocumentLoader schedules a substitute data load. An added benefit of this 31 approach is that ContentFilter can reuse CachedRawResource's original data buffer instead of keeping its own. 32 33 * loader/ContentFilter.cpp: 34 (WebCore::ContentFilter::createIfNeeded): Changed to take a DecisionFunction rather than a ResourceResponse and DocumentLoader. 35 (WebCore::ContentFilter::ContentFilter): Ditto. 36 (WebCore::ContentFilter::~ContentFilter): Removed ourself as a CachedRawResource client if needed. 37 (WebCore::ContentFilter::startFilteringMainResource): Became the client of the CachedRawResource in order to start the filtering process. 38 (WebCore::ContentFilter::unblockHandler): Returned the unblock handler. 39 (WebCore::ContentFilter::replacementData): Returned the replacement data. 40 (WebCore::ContentFilter::unblockRequestDeniedScript): Returned the unblock request denied script. 41 (WebCore::ContentFilter::responseReceived): Called responseReceived() on each filter using forEachContentFilterUntilBlocked(). 42 (WebCore::ContentFilter::dataReceived): Ditto for dataReceived(). 43 (WebCore::ContentFilter::notifyFinished): Ditto for finishedLoading(). 44 (WebCore::ContentFilter::forEachContentFilterUntilBlocked): For each filter that needs more data, called the function. 45 If the filter blocked the load, called didDecide() with State::Blocked. 46 If all filters allowed the load, called didDecide() with State::Allowed. 47 (WebCore::ContentFilter::didDecide): Set m_state and called m_decisionFunction(). 48 (WebCore::ContentFilter::addData): Deleted. 49 (WebCore::ContentFilter::finishedAddingData): Deleted. 50 (WebCore::ContentFilter::needsMoreData): Deleted. 51 (WebCore::ContentFilter::didBlockData): Deleted. 52 (WebCore::ContentFilter::getReplacementData): Deleted. 53 * loader/ContentFilter.h: 54 (WebCore::ContentFilter::type): 55 * loader/DocumentLoader.cpp: 56 (WebCore::DocumentLoader::DocumentLoader): Called ContentFilter::createIfNeeded() if not loading substitute data. 57 (WebCore::DocumentLoader::finishedLoading): Removed old ContentFilter code. 58 (WebCore::DocumentLoader::responseReceived): Ditto. 59 (WebCore::DocumentLoader::commitData): Ditto. 60 (WebCore::DocumentLoader::dataReceived): Ditto. 61 (WebCore::DocumentLoader::detachFromFrame): Set m_contentFilter to nullptr. 62 (WebCore::DocumentLoader::startLoadingMainResource): Called becomeMainResourceClientIfFilterAllows() instead of 63 becoming m_mainResource's client. 64 (WebCore::DocumentLoader::clearMainResource): Set m_contentFilter to nullptr. 65 (WebCore::DocumentLoader::becomeMainResourceClientIfFilterAllows): If ContentFilter is initialized, called 66 ContentFilter::startFilteringMainResource(). Otherwise added ourself as a client of m_mainResource. 67 (WebCore::DocumentLoader::installContentFilterUnblockHandler): Added a helper for creating and notifying 68 FrameLoaderClient of the unblock handler. 69 (WebCore::DocumentLoader::contentFilterDidDecide): Set m_contentFilter to nullptr. If the content filter 70 allowed the load, then added ourself as the CachedRawResource's client. Otherwise, installed the unblock handler 71 and scheduled a substitute data load with the replacement data. 72 * loader/DocumentLoader.h: 73 * loader/FrameLoader.cpp: 74 (WebCore::FrameLoader::prepareForLoadStart): Removed call to PolicyChecker::prepareForLoadStart(). 75 * loader/NavigationScheduler.cpp: 76 (WebCore::ScheduledSubstituteDataLoad::ScheduledSubstituteDataLoad): Added a ScheduledNavigation subclass that 77 calls FrameLoader::load() with a FrameLoadRequest containing substitute data. 78 (WebCore::NavigationScheduler::scheduleSubstituteDataLoad): Scheduled a substitute data load. 79 * loader/NavigationScheduler.h: 80 * loader/PolicyChecker.cpp: 81 (WebCore::PolicyChecker::checkNavigationPolicy): Reset m_contentFilterUnblockHandler if it couldn't handle the request. 82 (WebCore::PolicyChecker::prepareForLoadStart): Deleted. 83 * loader/PolicyChecker.h: 84 * platform/ContentFilterUnblockHandler.h: 85 (WebCore::ContentFilterUnblockHandler::unreachableURL): 86 (WebCore::ContentFilterUnblockHandler::setUnreachableURL): 87 (WebCore::ContentFilterUnblockHandler::unblockURLScheme): Renamed to ContentFilter::urlScheme(). 88 * platform/PlatformContentFilter.h: 89 * platform/cocoa/ContentFilterUnblockHandlerCocoa.mm: 90 (WebCore::ContentFilterUnblockHandler::wrapWithDecisionHandler): Added a helper to wrap the unblock handler with an outer DecisionHandlerFunction. 91 (WebCore::ContentFilterUnblockHandler::encode): Added m_unreachableURL to the encoding. 92 (WebCore::ContentFilterUnblockHandler::decode): Ditto for the decoding. 93 (WebCore::ContentFilterUnblockHandler::canHandleRequest): Changed to call ContentFilter::urlScheme(). 94 * platform/cocoa/NetworkExtensionContentFilter.h: 95 * platform/cocoa/NetworkExtensionContentFilter.mm: 96 (replacementDataFromDecisionInfo): Added a helper to extract replacement data from the decisionInfo dictionary. 97 (WebCore::NetworkExtensionContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled. 98 (WebCore::NetworkExtensionContentFilter::create): Created a new object. 99 (WebCore::NetworkExtensionContentFilter::NetworkExtensionContentFilter): Created a NEFilterSource immediately when using the modern API. 100 (WebCore::NetworkExtensionContentFilter::responseReceived): Created a NEFilterSource when using the legacy API. 101 Called -[NEFilterSource receivedResponse:decisionHandler:] when using the modern API. 102 (WebCore::NetworkExtensionContentFilter::addData): Stopped buffering the original data. 103 (WebCore::NetworkExtensionContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&. 104 (WebCore::NetworkExtensionContentFilter::canHandleResponse): Deleted. 105 (WebCore::createNEFilterSource): Deleted. 106 (WebCore::NetworkExtensionContentFilter::getReplacementData): Deleted. 107 * platform/cocoa/ParentalControlsContentFilter.h: 108 * platform/cocoa/ParentalControlsContentFilter.mm: 109 (WebCore::ParentalControlsContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled. 110 (WebCore::ParentalControlsContentFilter::create): Created a new object. 111 (WebCore::ParentalControlsContentFilter::ParentalControlsContentFilter): Initialized m_filterState to kWFEStateBuffering. 112 (WebCore::canHandleResponse): Added a helper to check if the response can be filtered. 113 (WebCore::ParentalControlsContentFilter::responseReceived): If !canHandleResponse(), set m_filterState to kWFEStateAllowed and return. 114 Otherwise created a new WebFilterEvaluator with the response. 115 (WebCore::ParentalControlsContentFilter::addData): Called updateFilterState(). 116 (WebCore::ParentalControlsContentFilter::finishedAddingData): Ditto. 117 (WebCore::ParentalControlsContentFilter::needsMoreData): Changed to check m_filterState. 118 (WebCore::ParentalControlsContentFilter::didBlockData): Ditto. 119 (WebCore::ParentalControlsContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&. 120 (WebCore::ParentalControlsContentFilter::updateFilterState): Updated m_filterState by calling -[WebFilterEvaluator filterState]. 121 (WebCore::ParentalControlsContentFilter::canHandleResponse): Deleted. 122 (WebCore::ParentalControlsContentFilter::getReplacementData): Deleted. 123 * platform/spi/cocoa/NEFilterSourceSPI.h: 124 * platform/spi/cocoa/WebFilterEvaluatorSPI.h: 125 * testing/MockContentFilter.cpp: 126 (WebCore::MockContentFilter::enabled): Renamed from canHandleReponse(); only checks if the filter is enabled. 127 (WebCore::MockContentFilter::create): Created a new object. 128 (WebCore::MockContentFilter::responseReceived): Called maybeDetermineStatus(). 129 (WebCore::MockContentFilter::addData): Stopped buffering the original data. 130 (WebCore::MockContentFilter::replacementData): Returned a SharedBuffer instead of a char* and int&. 131 (WebCore::MockContentFilter::unblockHandler): Asserted that we blocked data. 132 (WebCore::MockContentFilter::canHandleResponse): Deleted. 133 (WebCore::MockContentFilter::MockContentFilter): Deleted. 134 (WebCore::MockContentFilter::getReplacementData): Deleted. 135 * testing/MockContentFilter.h: 136 * testing/MockContentFilterSettings.cpp: 137 (WebCore::MockContentFilterSettings::unblockRequestURL): Changed to use a StringBuilder. 138 1 139 2015-04-04 Chris Fleizach <cfleizach@apple.com> 2 140 -
trunk/Source/WebCore/loader/ContentFilter.cpp
r181791 r182356 29 29 #if ENABLE(CONTENT_FILTERING) 30 30 31 #include " DocumentLoader.h"32 #include " Frame.h"31 #include "CachedRawResource.h" 32 #include "ContentFilterUnblockHandler.h" 33 33 #include "NetworkExtensionContentFilter.h" 34 34 #include "ParentalControlsContentFilter.h" 35 #include "ScriptController.h" 36 #include <bindings/ScriptValue.h> 35 #include "SharedBuffer.h" 37 36 #include <wtf/NeverDestroyed.h> 38 37 #include <wtf/Vector.h> … … 53 52 } 54 53 55 std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded( const ResourceResponse& response, DocumentLoader& documentLoader)54 std::unique_ptr<ContentFilter> ContentFilter::createIfNeeded(DecisionFunction decisionFunction) 56 55 { 57 56 Container filters; 58 57 for (auto& type : types()) { 59 if (type.canHandleResponse(response)) 60 filters.append(type.create(response)); 58 if (!type.enabled()) 59 continue; 60 61 auto filter = type.create(); 62 ASSERT(filter); 63 filters.append(WTF::move(filter)); 61 64 } 62 65 … … 64 67 return nullptr; 65 68 66 return std::make_unique<ContentFilter>(WTF::move(filters), documentLoader);69 return std::make_unique<ContentFilter>(WTF::move(filters), WTF::move(decisionFunction)); 67 70 } 68 71 69 ContentFilter::ContentFilter(Container contentFilters, D ocumentLoader& documentLoader)72 ContentFilter::ContentFilter(Container contentFilters, DecisionFunction decisionFunction) 70 73 : m_contentFilters { WTF::move(contentFilters) } 71 , m_d ocumentLoader { documentLoader}74 , m_decisionFunction { WTF::move(decisionFunction) } 72 75 { 73 76 ASSERT(!m_contentFilters.isEmpty()); 74 77 } 75 78 76 void ContentFilter::addData(const char* data, int length)79 ContentFilter::~ContentFilter() 77 80 { 78 ASSERT(needsMoreData()); 79 80 for (auto& contentFilter : m_contentFilters) 81 contentFilter->addData(data, length); 82 } 83 84 void ContentFilter::finishedAddingData() 85 { 86 ASSERT(needsMoreData()); 87 88 for (auto& contentFilter : m_contentFilters) 89 contentFilter->finishedAddingData(); 90 91 ASSERT(!needsMoreData()); 81 if (!m_mainResource) 82 return; 83 ASSERT(m_mainResource->hasClient(this)); 84 m_mainResource->removeClient(this); 92 85 } 93 86 94 bool ContentFilter::needsMoreData() const 87 void ContentFilter::startFilteringMainResource(CachedRawResource& resource) 95 88 { 96 for (auto& contentFilter : m_contentFilters) { 97 if (contentFilter->needsMoreData()) 98 return true; 99 } 100 101 return false; 102 } 103 104 bool ContentFilter::didBlockData() const 105 { 106 for (auto& contentFilter : m_contentFilters) { 107 if (contentFilter->didBlockData()) 108 return true; 109 } 110 111 return false; 112 } 113 114 const char* ContentFilter::getReplacementData(int& length) const 115 { 116 ASSERT(!needsMoreData()); 117 118 for (auto& contentFilter : m_contentFilters) { 119 if (contentFilter->didBlockData()) 120 return contentFilter->getReplacementData(length); 121 } 122 123 return m_contentFilters[0]->getReplacementData(length); 89 ASSERT(m_state == State::Initialized); 90 m_state = State::Filtering; 91 ASSERT(!m_mainResource); 92 m_mainResource = &resource; 93 ASSERT(!m_mainResource->hasClient(this)); 94 m_mainResource->addClient(this); 124 95 } 125 96 126 97 ContentFilterUnblockHandler ContentFilter::unblockHandler() const 127 98 { 128 ASSERT(didBlockData()); 99 ASSERT(m_state == State::Blocked); 100 ASSERT(m_blockingContentFilter); 101 ASSERT(m_blockingContentFilter->didBlockData()); 102 return m_blockingContentFilter->unblockHandler(); 103 } 129 104 130 PlatformContentFilter* blockingFilter = nullptr; 105 Ref<SharedBuffer> ContentFilter::replacementData() const 106 { 107 ASSERT(m_state == State::Blocked); 108 ASSERT(m_blockingContentFilter); 109 ASSERT(m_blockingContentFilter->didBlockData()); 110 return m_blockingContentFilter->replacementData(); 111 } 112 113 String ContentFilter::unblockRequestDeniedScript() const 114 { 115 ASSERT(m_state == State::Blocked); 116 ASSERT(m_blockingContentFilter); 117 ASSERT(m_blockingContentFilter->didBlockData()); 118 return m_blockingContentFilter->unblockRequestDeniedScript(); 119 } 120 121 void ContentFilter::responseReceived(CachedResource* resource, const ResourceResponse& response) 122 { 123 ASSERT(m_state == State::Filtering); 124 ASSERT_UNUSED(resource, resource == m_mainResource.get()); 125 forEachContentFilterUntilBlocked([&response](PlatformContentFilter& contentFilter) { 126 contentFilter.responseReceived(response); 127 }); 128 } 129 130 void ContentFilter::dataReceived(CachedResource* resource, const char* data, int length) 131 { 132 ASSERT(m_state == State::Filtering); 133 ASSERT_UNUSED(resource, resource == m_mainResource.get()); 134 forEachContentFilterUntilBlocked([data, length](PlatformContentFilter& contentFilter) { 135 contentFilter.addData(data, length); 136 }); 137 } 138 139 void ContentFilter::notifyFinished(CachedResource* resource) 140 { 141 ASSERT(m_state == State::Filtering); 142 ASSERT_UNUSED(resource, resource == m_mainResource.get()); 143 forEachContentFilterUntilBlocked([](PlatformContentFilter& contentFilter) { 144 contentFilter.finishedAddingData(); 145 }); 146 } 147 148 void ContentFilter::forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)> function) 149 { 150 bool allFiltersAllowedLoad { true }; 131 151 for (auto& contentFilter : m_contentFilters) { 152 if (!contentFilter->needsMoreData()) { 153 ASSERT(!contentFilter->didBlockData()); 154 continue; 155 } 156 157 function(*contentFilter); 158 132 159 if (contentFilter->didBlockData()) { 133 blockingFilter = contentFilter.get(); 134 break; 135 } 160 ASSERT(!m_blockingContentFilter); 161 m_blockingContentFilter = contentFilter.get(); 162 didDecide(State::Blocked); 163 return; 164 } else if (contentFilter->needsMoreData()) 165 allFiltersAllowedLoad = false; 136 166 } 137 ASSERT(blockingFilter);138 167 139 StringCapture unblockRequestDeniedScript { blockingFilter->unblockRequestDeniedScript() };140 if (unblockRequestDeniedScript.string().isEmpty())141 return blockingFilter->unblockHandler(); 168 if (allFiltersAllowedLoad) 169 didDecide(State::Allowed); 170 } 142 171 143 // It would be a layering violation for the unblock handler to access its frame, 144 // so we will execute the unblock denied script on its behalf. 145 ContentFilterUnblockHandler unblockHandler { blockingFilter->unblockHandler() }; 146 RefPtr<Frame> frame { m_documentLoader.frame() }; 147 return ContentFilterUnblockHandler { 148 unblockHandler.unblockURLHost(), [unblockHandler, frame, unblockRequestDeniedScript](ContentFilterUnblockHandler::DecisionHandlerFunction decisionHandler) { 149 unblockHandler.requestUnblockAsync([decisionHandler, frame, unblockRequestDeniedScript](bool unblocked) { 150 decisionHandler(unblocked); 151 if (!unblocked && frame) 152 frame->script().executeScript(unblockRequestDeniedScript.string()); 153 }); 154 } 155 }; 172 void ContentFilter::didDecide(State state) 173 { 174 ASSERT(m_state != State::Allowed); 175 ASSERT(m_state != State::Blocked); 176 ASSERT(state == State::Allowed || state == State::Blocked); 177 m_state = state; 178 179 // Calling m_decisionFunction might delete |this|. 180 if (m_decisionFunction) 181 m_decisionFunction(); 156 182 } 157 183 -
trunk/Source/WebCore/loader/ContentFilter.h
r181791 r182356 29 29 #if ENABLE(CONTENT_FILTERING) 30 30 31 #include "PlatformContentFilter.h" 31 #include "CachedRawResourceClient.h" 32 #include "CachedResourceHandle.h" 33 #include <functional> 32 34 #include <wtf/Vector.h> 33 35 34 36 namespace WebCore { 35 37 36 class DocumentLoader; 37 class ResourceResponse; 38 class CachedRawResource; 39 class ContentFilterUnblockHandler; 40 class PlatformContentFilter; 41 class SharedBuffer; 38 42 39 class ContentFilter final : public PlatformContentFilter { 43 class ContentFilter final : private CachedRawResourceClient { 44 WTF_MAKE_FAST_ALLOCATED; 45 WTF_MAKE_NONCOPYABLE(ContentFilter); 46 40 47 public: 41 48 template <typename T> static void addType() { types().append(type<T>()); } 42 static std::unique_ptr<ContentFilter> createIfNeeded(const ResourceResponse&, DocumentLoader&);43 49 44 void addData(const char* data, int length) override; 45 void finishedAddingData() override; 46 bool needsMoreData() const override; 47 bool didBlockData() const override; 48 const char* getReplacementData(int& length) const override; 49 ContentFilterUnblockHandler unblockHandler() const override; 50 using DecisionFunction = std::function<void()>; 51 static std::unique_ptr<ContentFilter> createIfNeeded(DecisionFunction); 52 ~ContentFilter() override; 53 54 static const char* urlScheme() { return "x-apple-content-filter"; } 55 56 void startFilteringMainResource(CachedRawResource&); 57 58 enum class State { 59 Initialized, 60 Filtering, 61 Allowed, 62 Blocked 63 }; 64 State state() const { return m_state; } 65 ContentFilterUnblockHandler unblockHandler() const; 66 Ref<SharedBuffer> replacementData() const; 67 String unblockRequestDeniedScript() const; 50 68 51 69 private: 52 70 struct Type { 53 const std::function<bool( const ResourceResponse&)> canHandleResponse;54 const std::function<std::unique_ptr<PlatformContentFilter>( const ResourceResponse&)> create;71 const std::function<bool()> enabled; 72 const std::function<std::unique_ptr<PlatformContentFilter>()> create; 55 73 }; 56 74 template <typename T> static Type type(); … … 58 76 59 77 using Container = Vector<std::unique_ptr<PlatformContentFilter>>; 60 friend std::unique_ptr<ContentFilter> std::make_unique<ContentFilter>(Container&&, D ocumentLoader&);61 explicit ContentFilter(Container, DocumentLoader&);78 friend std::unique_ptr<ContentFilter> std::make_unique<ContentFilter>(Container&&, DecisionFunction&&); 79 ContentFilter(Container, DecisionFunction); 62 80 63 Container m_contentFilters; 64 DocumentLoader& m_documentLoader; 81 // CachedRawResourceClient 82 void responseReceived(CachedResource*, const ResourceResponse&) override; 83 void dataReceived(CachedResource*, const char* data, int length) override; 84 85 // CachedResourceClient 86 void notifyFinished(CachedResource*) override; 87 88 void forEachContentFilterUntilBlocked(std::function<void(PlatformContentFilter&)>); 89 void didDecide(State); 90 91 const Container m_contentFilters; 92 const DecisionFunction m_decisionFunction; 93 CachedResourceHandle<CachedRawResource> m_mainResource; 94 PlatformContentFilter* m_blockingContentFilter { nullptr }; 95 State m_state { State::Initialized }; 65 96 }; 66 97 … … 69 100 { 70 101 static_assert(std::is_base_of<PlatformContentFilter, T>::value, "Type must be a PlatformContentFilter."); 71 return { T:: canHandleResponse, T::create };102 return { T::enabled, T::create }; 72 103 } 73 104 -
trunk/Source/WebCore/loader/DocumentLoader.cpp
r181876 r182356 59 59 #include "ResourceHandle.h" 60 60 #include "SchemeRegistry.h" 61 #include "ScriptController.h" 61 62 #include "SecurityPolicy.h" 62 63 #include "Settings.h" … … 141 142 , m_subresourceLoadersArePageCacheAcceptable(false) 142 143 , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(*this))) 144 #if ENABLE(CONTENT_FILTERING) 145 , m_contentFilter(!substituteData.isValid() ? ContentFilter::createIfNeeded(std::bind(&DocumentLoader::contentFilterDidDecide, this)) : nullptr) 146 #endif 143 147 { 144 148 } … … 401 405 frameLoader()->notifier().dispatchDidFinishLoading(this, identifier, finishTime); 402 406 } 403 404 #if ENABLE(CONTENT_FILTERING)405 if (m_contentFilter && m_contentFilter->needsMoreData()) {406 m_contentFilter->finishedAddingData();407 int length;408 const char* data = m_contentFilter->getReplacementData(length);409 if (data)410 dataReceived(m_mainResource.get(), data, length);411 412 if (m_contentFilter->didBlockData()) {413 frameLoader()->client().contentFilterDidBlockLoad(m_contentFilter->unblockHandler());414 m_contentFilter = nullptr;415 }416 }417 #endif418 407 419 408 maybeFinishLoadingMultipartContent(); … … 663 652 #endif 664 653 665 #if ENABLE(CONTENT_FILTERING)666 m_contentFilter = ContentFilter::createIfNeeded(response, *this);667 #endif668 669 654 frameLoader()->policyChecker().checkContentPolicy(m_response, [this](PolicyAction policy) { 670 655 continueAfterContentPolicy(policy); … … 819 804 bool userChosen; 820 805 String encoding; 821 #if ENABLE(CONTENT_FILTERING)822 // The content filter's replacement data has a known encoding that might823 // differ from the response's encoding.824 if (m_contentFilter && m_contentFilter->didBlockData()) {825 ASSERT(!m_contentFilter->needsMoreData());826 userChosen = false;827 } else828 #endif829 806 if (overrideEncoding().isNull()) { 830 807 userChosen = false; … … 871 848 #endif 872 849 873 #if ENABLE(CONTENT_FILTERING)874 bool loadWasBlockedBeforeFinishing = false;875 if (m_contentFilter && m_contentFilter->needsMoreData()) {876 m_contentFilter->addData(data, length);877 878 if (m_contentFilter->needsMoreData()) {879 // Since the filter still needs more data to make a decision,880 // avoid committing this data to prevent partial rendering of881 // content that might later be blocked.882 return;883 }884 885 data = m_contentFilter->getReplacementData(length);886 loadWasBlockedBeforeFinishing = m_contentFilter->didBlockData();887 888 if (loadWasBlockedBeforeFinishing)889 frameLoader()->client().contentFilterDidBlockLoad(m_contentFilter->unblockHandler());890 }891 #endif892 893 850 if (m_identifierForLoadWithoutResourceLoader) 894 851 frameLoader()->notifier().dispatchDidReceiveData(this, m_identifierForLoadWithoutResourceLoader, data, length, -1); … … 899 856 if (!isMultipartReplacingLoad()) 900 857 commitLoad(data, length); 901 902 #if ENABLE(CONTENT_FILTERING)903 if (loadWasBlockedBeforeFinishing) {904 cancelMainResourceLoad(frameLoader()->cancelledError(m_request));905 m_contentFilter = nullptr;906 }907 #endif908 858 } 909 859 … … 961 911 if (m_mainResource && m_mainResource->hasClient(this)) 962 912 m_mainResource->removeClient(this); 913 #if ENABLE(CONTENT_FILTERING) 914 m_contentFilter = nullptr; 915 #endif 963 916 964 917 m_applicationCacheHost->setDOMApplicationCache(nullptr); … … 1472 1425 frameLoader()->notifier().dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, request, ResourceResponse()); 1473 1426 } 1427 1428 #if ENABLE(CONTENT_FILTERING) 1429 becomeMainResourceClientIfFilterAllows(); 1430 #else 1474 1431 m_mainResource->addClient(this); 1432 #endif 1475 1433 1476 1434 // A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those. … … 1508 1466 if (m_mainResource && m_mainResource->hasClient(this)) 1509 1467 m_mainResource->removeClient(this); 1468 #if ENABLE(CONTENT_FILTERING) 1469 m_contentFilter = nullptr; 1470 #endif 1510 1471 1511 1472 m_mainResource = 0; … … 1601 1562 #endif 1602 1563 1564 #if ENABLE(CONTENT_FILTERING) 1565 void DocumentLoader::becomeMainResourceClientIfFilterAllows() 1566 { 1567 ASSERT(m_mainResource); 1568 if (m_contentFilter) { 1569 ASSERT(m_contentFilter->state() == ContentFilter::State::Initialized); 1570 m_contentFilter->startFilteringMainResource(*m_mainResource); 1571 } else 1572 m_mainResource->addClient(this); 1573 } 1574 1575 void DocumentLoader::installContentFilterUnblockHandler(ContentFilter& contentFilter) 1576 { 1577 ContentFilterUnblockHandler unblockHandler { contentFilter.unblockHandler() }; 1578 unblockHandler.setUnreachableURL(documentURL()); 1579 RefPtr<Frame> frame { this->frame() }; 1580 String unblockRequestDeniedScript { contentFilter.unblockRequestDeniedScript() }; 1581 if (!unblockRequestDeniedScript.isEmpty() && frame) { 1582 static_assert(std::is_base_of<ThreadSafeRefCounted<Frame>, Frame>::value, "Frame must be ThreadSafeRefCounted."); 1583 StringCapture capturedScript { unblockRequestDeniedScript }; 1584 unblockHandler.wrapWithDecisionHandler([frame, capturedScript](bool unblocked) { 1585 if (!unblocked) 1586 frame->script().executeScript(capturedScript.string()); 1587 }); 1588 } 1589 frameLoader()->client().contentFilterDidBlockLoad(WTF::move(unblockHandler)); 1590 } 1591 1592 void DocumentLoader::contentFilterDidDecide() 1593 { 1594 using State = ContentFilter::State; 1595 ASSERT(m_contentFilter); 1596 ASSERT(m_contentFilter->state() == State::Blocked || m_contentFilter->state() == State::Allowed); 1597 std::unique_ptr<ContentFilter> contentFilter; 1598 std::swap(contentFilter, m_contentFilter); 1599 if (contentFilter->state() == State::Allowed) { 1600 if (m_mainResource) 1601 m_mainResource->addClient(this); 1602 return; 1603 } 1604 1605 installContentFilterUnblockHandler(*contentFilter); 1606 1607 URL blockedURL; 1608 blockedURL.setProtocol(ContentFilter::urlScheme()); 1609 blockedURL.setHost(ASCIILiteral("blocked-page")); 1610 SubstituteData substituteData { contentFilter->replacementData(), ASCIILiteral("text/html"), ASCIILiteral("UTF-8"), documentURL() }; 1611 frame()->navigationScheduler().scheduleSubstituteDataLoad(blockedURL, substituteData); 1612 } 1613 #endif 1614 1615 1603 1616 } // namespace WebCore -
trunk/Source/WebCore/loader/DocumentLoader.h
r181876 r182356 65 65 class CachedRawResource; 66 66 class CachedResourceLoader; 67 class ContentFilter;68 67 class FormState; 69 68 class Frame; … … 73 72 class SharedBuffer; 74 73 class SubstituteResource; 74 75 #if ENABLE(CONTENT_FILTERING) 76 class ContentFilter; 77 #endif 75 78 76 79 typedef HashMap<unsigned long, RefPtr<ResourceLoader>> ResourceLoaderMap; … … 331 334 void clearMainResource(); 332 335 336 #if ENABLE(CONTENT_FILTERING) 337 void becomeMainResourceClientIfFilterAllows(); 338 void installContentFilterUnblockHandler(ContentFilter&); 339 void contentFilterDidDecide(); 340 #endif 341 333 342 Frame* m_frame; 334 343 Ref<CachedResourceLoader> m_cachedResourceLoader; -
trunk/Source/WebCore/loader/FrameLoader.cpp
r182351 r182356 1125 1125 void FrameLoader::prepareForLoadStart() 1126 1126 { 1127 policyChecker().prepareForLoadStart();1128 1127 m_progressTracker->progressStarted(); 1129 1128 m_client.dispatchDidStartProvisionalLoad(); -
trunk/Source/WebCore/loader/NavigationScheduler.cpp
r180110 r182356 279 279 }; 280 280 281 class ScheduledSubstituteDataLoad : public ScheduledNavigation { 282 public: 283 ScheduledSubstituteDataLoad(const URL& baseURL, const SubstituteData& substituteData) 284 : ScheduledNavigation { 0, LockHistory::No, LockBackForwardList::No, false, false } 285 , m_baseURL { baseURL } 286 , m_substituteData { substituteData } 287 { 288 } 289 290 void fire(Frame& frame) override 291 { 292 UserGestureIndicator gestureIndicator { wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture }; 293 frame.loader().load(FrameLoadRequest { &frame, m_baseURL, m_substituteData }); 294 } 295 296 private: 297 URL m_baseURL; 298 SubstituteData m_substituteData; 299 }; 300 281 301 NavigationScheduler::NavigationScheduler(Frame& frame) 282 302 : m_frame(frame) … … 431 451 } 432 452 453 void NavigationScheduler::scheduleSubstituteDataLoad(const URL& baseURL, const SubstituteData& substituteData) 454 { 455 if (shouldScheduleNavigation()) 456 schedule(std::make_unique<ScheduledSubstituteDataLoad>(baseURL, substituteData)); 457 } 458 433 459 void NavigationScheduler::timerFired() 434 460 { -
trunk/Source/WebCore/loader/NavigationScheduler.h
r176459 r182356 42 42 class ScheduledNavigation; 43 43 class SecurityOrigin; 44 class SubstituteData; 44 45 class URL; 45 46 … … 74 75 void scheduleRefresh(); 75 76 void scheduleHistoryNavigation(int steps); 77 void scheduleSubstituteDataLoad(const URL& baseURL, const SubstituteData&); 76 78 77 79 void startTimer(); -
trunk/Source/WebCore/loader/PolicyChecker.cpp
r181791 r182356 57 57 } 58 58 59 void PolicyChecker::prepareForLoadStart()60 {61 #if ENABLE(CONTENT_FILTERING)62 m_contentFilterUnblockHandler = { };63 #endif64 }65 66 59 void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function) 67 60 { … … 121 114 }); 122 115 continueAfterNavigationPolicy(PolicyIgnore); 123 } 116 return; 117 } 118 m_contentFilterUnblockHandler = { }; 124 119 #endif 125 120 -
trunk/Source/WebCore/loader/PolicyChecker.h
r181791 r182356 55 55 explicit PolicyChecker(Frame&); 56 56 57 void prepareForLoadStart();58 57 void checkNavigationPolicy(const ResourceRequest&, DocumentLoader*, PassRefPtr<FormState>, NavigationPolicyDecisionFunction); 59 58 void checkNavigationPolicy(const ResourceRequest&, NavigationPolicyDecisionFunction); -
trunk/Source/WebCore/platform/ContentFilterUnblockHandler.h
r181791 r182356 29 29 #if ENABLE(CONTENT_FILTERING) 30 30 31 #include "URL.h" 31 32 #include <functional> 32 33 #include <wtf/RetainPtr.h> … … 48 49 using UnblockRequesterFunction = std::function<void(DecisionHandlerFunction)>; 49 50 50 static const char* unblockURLScheme() { return "x-apple-content-filter"; }51 52 51 ContentFilterUnblockHandler() = default; 53 52 WEBCORE_EXPORT ContentFilterUnblockHandler(String unblockURLHost, UnblockRequesterFunction); … … 61 60 WEBCORE_EXPORT bool canHandleRequest(const ResourceRequest&) const; 62 61 WEBCORE_EXPORT void requestUnblockAsync(DecisionHandlerFunction) const; 62 void wrapWithDecisionHandler(const DecisionHandlerFunction&); 63 63 64 64 const String& unblockURLHost() const { return m_unblockURLHost; } 65 const URL& unreachableURL() const { return m_unreachableURL; } 66 void setUnreachableURL(const URL& url) { m_unreachableURL = url; } 65 67 66 68 private: 67 69 String m_unblockURLHost; 70 URL m_unreachableURL; 68 71 UnblockRequesterFunction m_unblockRequester; 69 72 #if PLATFORM(IOS) -
trunk/Source/WebCore/platform/PlatformContentFilter.h
r181791 r182356 27 27 #define PlatformContentFilter_h 28 28 29 #include "ContentFilterUnblockHandler.h"29 #include <wtf/Ref.h> 30 30 #include <wtf/text/WTFString.h> 31 31 32 32 namespace WebCore { 33 33 34 class ContentFilterUnblockHandler; 34 35 class ResourceResponse; 36 class SharedBuffer; 35 37 36 38 class PlatformContentFilter { … … 43 45 public: 44 46 virtual ~PlatformContentFilter() { } 47 virtual void responseReceived(const ResourceResponse&) = 0; 45 48 virtual void addData(const char* data, int length) = 0; 46 49 virtual void finishedAddingData() = 0; 47 50 virtual bool needsMoreData() const = 0; 48 51 virtual bool didBlockData() const = 0; 49 virtual const char* getReplacementData(int& length) const = 0;52 virtual Ref<SharedBuffer> replacementData() const = 0; 50 53 virtual ContentFilterUnblockHandler unblockHandler() const = 0; 51 54 virtual String unblockRequestDeniedScript() const { return emptyString(); } -
trunk/Source/WebCore/platform/cocoa/ContentFilterUnblockHandlerCocoa.mm
r181791 r182356 30 30 31 31 #import "BlockExceptions.h" 32 #import "ContentFilter.h" 32 33 #import "ResourceRequest.h" 33 34 … … 44 45 45 46 static NSString * const unblockURLHostKey { @"unblockURLHost" }; 47 static NSString * const unreachableURLKey { @"unreachableURL" }; 46 48 47 49 namespace WebCore { … … 61 63 #endif 62 64 65 void ContentFilterUnblockHandler::wrapWithDecisionHandler(const DecisionHandlerFunction& decisionHandler) 66 { 67 ContentFilterUnblockHandler wrapped { *this }; 68 UnblockRequesterFunction wrappedRequester { [wrapped, decisionHandler](DecisionHandlerFunction wrappedDecisionHandler) { 69 wrapped.requestUnblockAsync([wrappedDecisionHandler, decisionHandler](bool unblocked) { 70 wrappedDecisionHandler(unblocked); 71 decisionHandler(unblocked); 72 }); 73 }}; 74 #if PLATFORM(IOS) 75 m_webFilterEvaluator = nullptr; 76 #endif 77 std::swap(m_unblockRequester, wrappedRequester); 78 } 79 63 80 bool ContentFilterUnblockHandler::needsUIProcess() const 64 81 { … … 75 92 BEGIN_BLOCK_OBJC_EXCEPTIONS; 76 93 [coder encodeObject:m_unblockURLHost forKey:unblockURLHostKey]; 94 [coder encodeObject:(NSURL *)m_unreachableURL forKey:unreachableURLKey]; 77 95 #if PLATFORM(IOS) 78 96 [coder encodeObject:m_webFilterEvaluator.get() forKey:webFilterEvaluatorKey]; … … 86 104 BEGIN_BLOCK_OBJC_EXCEPTIONS; 87 105 unblockHandler.m_unblockURLHost = [coder decodeObjectOfClass:[NSString class] forKey:unblockURLHostKey]; 106 unblockHandler.m_unreachableURL = [coder decodeObjectOfClass:[NSURL class] forKey:unreachableURLKey]; 88 107 #if PLATFORM(IOS) 89 108 unblockHandler.m_webFilterEvaluator = [coder decodeObjectOfClass:getWebFilterEvaluatorClass() forKey:webFilterEvaluatorKey]; … … 105 124 } 106 125 107 return request.url().protocolIs( unblockURLScheme()) && equalIgnoringCase(request.url().host(), m_unblockURLHost);126 return request.url().protocolIs(ContentFilter::urlScheme()) && equalIgnoringCase(request.url().host(), m_unblockURLHost); 108 127 } 109 128 -
trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h
r181781 r182356 28 28 29 29 #include "PlatformContentFilter.h" 30 #include "SharedBuffer.h"31 30 #include <objc/NSObjCRuntime.h> 32 31 #include <wtf/Compiler.h> 33 32 #include <wtf/OSObjectPtr.h> 34 #include <wtf/Ref.h>35 33 #include <wtf/RetainPtr.h> 36 34 … … 43 41 OBJC_CLASS NSDictionary; 44 42 OBJC_CLASS NSMutableData; 45 43 OBJC_CLASS NSString; 46 44 namespace WebCore { 47 45 48 46 class NetworkExtensionContentFilter final : public PlatformContentFilter { 49 friend std::unique_ptr<NetworkExtensionContentFilter> std::make_unique<NetworkExtensionContentFilter>( const ResourceResponse&);47 friend std::unique_ptr<NetworkExtensionContentFilter> std::make_unique<NetworkExtensionContentFilter>(); 50 48 51 49 public: 52 static bool canHandleResponse(const ResourceResponse&);53 static std::unique_ptr<NetworkExtensionContentFilter> create( const ResourceResponse&);50 static bool enabled(); 51 static std::unique_ptr<NetworkExtensionContentFilter> create(); 54 52 53 void responseReceived(const ResourceResponse&) override; 55 54 void addData(const char* data, int length) override; 56 55 void finishedAddingData() override; 57 56 bool needsMoreData() const override; 58 57 bool didBlockData() const override; 59 const char* getReplacementData(int& length) const override;58 Ref<SharedBuffer> replacementData() const override; 60 59 ContentFilterUnblockHandler unblockHandler() const override; 61 60 62 61 private: 63 explicit NetworkExtensionContentFilter(const ResourceResponse&);62 NetworkExtensionContentFilter(); 64 63 void handleDecision(NEFilterSourceStatus, NSData *replacementData); 65 64 … … 67 66 OSObjectPtr<dispatch_queue_t> m_queue; 68 67 OSObjectPtr<dispatch_semaphore_t> m_semaphore; 69 Ref<SharedBuffer> m_originalData;70 68 RetainPtr<NSData> m_replacementData; 71 69 RetainPtr<NEFilterSource> m_neFilterSource; -
trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm
r181795 r182356 29 29 #if HAVE(NETWORK_EXTENSION) 30 30 31 #import "ContentFilterUnblockHandler.h" 31 32 #import "NEFilterSourceSPI.h" 32 33 #import "ResourceResponse.h" 34 #import "SharedBuffer.h" 33 35 #import "SoftLinking.h" 36 #import "URL.h" 34 37 #import <objc/runtime.h> 35 38 … … 38 41 39 42 #if HAVE(MODERN_NE_FILTER_SOURCE) 40 // FIXME: <rdar://problem/20165664> Expose decisionHandler dictionary keys as NSString constants in NEFilterSource.h41 static NSString * const optionsPageData = @"PageData";42 43 43 static inline NSData *replacementDataFromDecisionInfo(NSDictionary *decisionInfo) 44 44 { 45 id replacementData = decisionInfo[ optionsPageData];45 id replacementData = decisionInfo[NEFilterSourceOptionsPageData]; 46 46 ASSERT(!replacementData || [replacementData isKindOfClass:[NSData class]]); 47 47 return replacementData; … … 51 51 namespace WebCore { 52 52 53 bool NetworkExtensionContentFilter:: canHandleResponse(const ResourceResponse& response)53 bool NetworkExtensionContentFilter::enabled() 54 54 { 55 return response.url().protocolIsInHTTPFamily() &&[getNEFilterSourceClass() filterRequired];55 return [getNEFilterSourceClass() filterRequired]; 56 56 } 57 57 58 std::unique_ptr<NetworkExtensionContentFilter> NetworkExtensionContentFilter::create( const ResourceResponse& response)58 std::unique_ptr<NetworkExtensionContentFilter> NetworkExtensionContentFilter::create() 59 59 { 60 return std::make_unique<NetworkExtensionContentFilter>( response);60 return std::make_unique<NetworkExtensionContentFilter>(); 61 61 } 62 62 63 static inline RetainPtr<NEFilterSource> createNEFilterSource(const URL& url, dispatch_queue_t decisionQueue) 64 { 65 #if HAVE(MODERN_NE_FILTER_SOURCE) 66 UNUSED_PARAM(url); 67 return adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:decisionQueue]); 68 #else 69 UNUSED_PARAM(decisionQueue); 70 return adoptNS([allocNEFilterSourceInstance() initWithURL:url direction:NEFilterSourceDirectionInbound socketIdentifier:0]); 71 #endif 72 } 73 74 NetworkExtensionContentFilter::NetworkExtensionContentFilter(const ResourceResponse& response) 63 NetworkExtensionContentFilter::NetworkExtensionContentFilter() 75 64 : m_status { NEFilterSourceStatusNeedsMoreData } 76 65 , m_queue { adoptOSObject(dispatch_queue_create("com.apple.WebCore.NEFilterSourceQueue", DISPATCH_QUEUE_SERIAL)) } 77 66 , m_semaphore { adoptOSObject(dispatch_semaphore_create(0)) } 78 , m_originalData { *SharedBuffer::create() } 79 , m_neFilterSource { createNEFilterSource(response.url(), m_queue.get()) } 67 #if HAVE(MODERN_NE_FILTER_SOURCE) 68 , m_neFilterSource { adoptNS([allocNEFilterSourceInstance() initWithDecisionQueue:m_queue.get()]) } 69 #endif 80 70 { 81 71 ASSERT([getNEFilterSourceClass() filterRequired]); 72 } 82 73 83 #if HAVE(MODERN_NE_FILTER_SOURCE) 74 void NetworkExtensionContentFilter::responseReceived(const ResourceResponse& response) 75 { 76 if (!response.url().protocolIsInHTTPFamily()) { 77 m_status = NEFilterSourceStatusPass; 78 return; 79 } 80 81 #if !HAVE(MODERN_NE_FILTER_SOURCE) 82 ASSERT(!m_neFilterSource); 83 m_neFilterSource = adoptNS([allocNEFilterSourceInstance() initWithURL:response.url() direction:NEFilterSourceDirectionInbound socketIdentifier:0]); 84 #else 84 85 [m_neFilterSource receivedResponse:response.nsURLResponse() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) { 85 86 handleDecision(status, replacementDataFromDecisionInfo(decisionInfo)); … … 96 97 { 97 98 RetainPtr<NSData> copiedData { [NSData dataWithBytes:(void*)data length:length] }; 98 99 // FIXME: NEFilterSource doesn't buffer data like WebFilterEvaluator does,100 // so we need to do it ourselves so getReplacementData() can return the101 // original bytes back to the loader. We should find a way to remove this102 // additional copy.103 m_originalData->append((CFDataRef)copiedData.get());104 99 105 100 #if HAVE(MODERN_NE_FILTER_SOURCE) … … 149 144 } 150 145 151 const char* NetworkExtensionContentFilter::getReplacementData(int& length) const146 Ref<SharedBuffer> NetworkExtensionContentFilter::replacementData() const 152 147 { 153 if (didBlockData()) { 154 length = [m_replacementData length]; 155 return static_cast<const char*>([m_replacementData bytes]); 156 } 157 158 length = m_originalData->size(); 159 return m_originalData->data(); 148 ASSERT(didBlockData()); 149 return adoptRef(*SharedBuffer::wrapNSData(m_replacementData.get()).leakRef()); 160 150 } 161 151 -
trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.h
r181781 r182356 37 37 38 38 class ParentalControlsContentFilter final : public PlatformContentFilter { 39 friend std::unique_ptr<ParentalControlsContentFilter> std::make_unique<ParentalControlsContentFilter>( const ResourceResponse&);39 friend std::unique_ptr<ParentalControlsContentFilter> std::make_unique<ParentalControlsContentFilter>(); 40 40 41 41 public: 42 static bool canHandleResponse(const ResourceResponse&);43 static std::unique_ptr<ParentalControlsContentFilter> create( const ResourceResponse&);42 static bool enabled(); 43 static std::unique_ptr<ParentalControlsContentFilter> create(); 44 44 45 void responseReceived(const ResourceResponse&) override; 45 46 void addData(const char* data, int length) override; 46 47 void finishedAddingData() override; 47 48 bool needsMoreData() const override; 48 49 bool didBlockData() const override; 49 const char* getReplacementData(int& length) const override;50 Ref<SharedBuffer> replacementData() const override; 50 51 ContentFilterUnblockHandler unblockHandler() const override; 51 52 52 53 private: 53 explicit ParentalControlsContentFilter(const ResourceResponse&); 54 ParentalControlsContentFilter(); 55 void updateFilterState(); 54 56 57 OSStatus m_filterState; 55 58 RetainPtr<WebFilterEvaluator> m_webFilterEvaluator; 56 59 RetainPtr<NSData> m_replacementData; -
trunk/Source/WebCore/platform/cocoa/ParentalControlsContentFilter.mm
r181795 r182356 27 27 #import "ParentalControlsContentFilter.h" 28 28 29 #import "ContentFilterUnblockHandler.h" 29 30 #import "ResourceResponse.h" 31 #import "SharedBuffer.h" 30 32 #import "SoftLinking.h" 31 33 #import "WebFilterEvaluatorSPI.h" … … 37 39 namespace WebCore { 38 40 39 bool ParentalControlsContentFilter:: canHandleResponse(const ResourceResponse& response)41 bool ParentalControlsContentFilter::enabled() 40 42 { 41 if (!response.url().protocolIsInHTTPFamily())42 return false; 43 return [getWebFilterEvaluatorClass() isManagedSession]; 44 } 43 45 44 if ([getWebFilterEvaluatorClass() isManagedSession]) { 46 std::unique_ptr<ParentalControlsContentFilter> ParentalControlsContentFilter::create() 47 { 48 return std::make_unique<ParentalControlsContentFilter>(); 49 } 50 51 ParentalControlsContentFilter::ParentalControlsContentFilter() 52 : m_filterState { kWFEStateBuffering } 53 { 54 ASSERT([getWebFilterEvaluatorClass() isManagedSession]); 55 } 56 57 static inline bool canHandleResponse(const ResourceResponse& response) 58 { 45 59 #if PLATFORM(MAC) 46 if (response.url().protocolIs("https")) 60 return response.url().protocolIs("https"); 61 #else 62 return response.url().protocolIsInHTTPFamily(); 47 63 #endif 48 return true; 64 } 65 66 void ParentalControlsContentFilter::responseReceived(const ResourceResponse& response) 67 { 68 ASSERT(!m_webFilterEvaluator); 69 70 if (!canHandleResponse(response)) { 71 m_filterState = kWFEStateAllowed; 72 return; 49 73 } 50 74 51 return false; 52 } 53 54 std::unique_ptr<ParentalControlsContentFilter> ParentalControlsContentFilter::create(const ResourceResponse& response) 55 { 56 return std::make_unique<ParentalControlsContentFilter>(response); 57 } 58 59 ParentalControlsContentFilter::ParentalControlsContentFilter(const ResourceResponse& response) 60 : m_webFilterEvaluator { adoptNS([allocWebFilterEvaluatorInstance() initWithResponse:response.nsURLResponse()]) } 61 { 62 ASSERT([getWebFilterEvaluatorClass() isManagedSession]); 75 m_webFilterEvaluator = adoptNS([allocWebFilterEvaluatorInstance() initWithResponse:response.nsURLResponse()]); 76 updateFilterState(); 63 77 } 64 78 … … 67 81 ASSERT(![m_replacementData.get() length]); 68 82 m_replacementData = [m_webFilterEvaluator addData:[NSData dataWithBytesNoCopy:(void*)data length:length freeWhenDone:NO]]; 83 updateFilterState(); 69 84 ASSERT(needsMoreData() || [m_replacementData.get() length]); 70 85 } … … 74 89 ASSERT(![m_replacementData.get() length]); 75 90 m_replacementData = [m_webFilterEvaluator dataComplete]; 91 updateFilterState(); 76 92 } 77 93 78 94 bool ParentalControlsContentFilter::needsMoreData() const 79 95 { 80 return [m_webFilterEvaluator filterState]== kWFEStateBuffering;96 return m_filterState == kWFEStateBuffering; 81 97 } 82 98 83 99 bool ParentalControlsContentFilter::didBlockData() const 84 100 { 85 return [m_webFilterEvaluator wasBlocked];101 return m_filterState == kWFEStateBlocked; 86 102 } 87 103 88 const char* ParentalControlsContentFilter::getReplacementData(int& length) const104 Ref<SharedBuffer> ParentalControlsContentFilter::replacementData() const 89 105 { 90 length = [m_replacementData length];91 return static_cast<const char*>([m_replacementData bytes]);106 ASSERT(didBlockData()); 107 return adoptRef(*SharedBuffer::wrapNSData(m_replacementData.get()).leakRef()); 92 108 } 93 109 … … 101 117 } 102 118 119 void ParentalControlsContentFilter::updateFilterState() 120 { 121 m_filterState = [m_webFilterEvaluator filterState]; 122 } 123 103 124 } // namespace WebCore -
trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h
r181523 r182356 69 69 - (void)remediateWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler; 70 70 @end 71 71 72 #endif 72 73 -
trunk/Source/WebCore/platform/spi/cocoa/WebFilterEvaluatorSPI.h
r180872 r182356 33 33 34 34 enum { 35 kWFEStateBuffering = 2 35 kWFEStateAllowed = 0, 36 kWFEStateBlocked = 1, 37 kWFEStateBuffering = 2, 38 kWFEStateEvaluating = 3 36 39 }; 37 40 -
trunk/Source/WebCore/testing/MockContentFilter.cpp
r181791 r182356 30 30 31 31 #include "ContentFilter.h" 32 #include "ContentFilterUnblockHandler.h" 33 #include "SharedBuffer.h" 32 34 #include <mutex> 33 35 #include <wtf/text/CString.h> 36 #include <wtf/text/StringBuilder.h> 34 37 35 38 namespace WebCore { … … 51 54 } 52 55 53 bool MockContentFilter:: canHandleResponse(const ResourceResponse&)56 bool MockContentFilter::enabled() 54 57 { 55 58 return settings().enabled(); 56 59 } 57 60 58 std::unique_ptr<MockContentFilter> MockContentFilter::create( const ResourceResponse& response)61 std::unique_ptr<MockContentFilter> MockContentFilter::create() 59 62 { 60 return std::make_unique<MockContentFilter>( response);63 return std::make_unique<MockContentFilter>(); 61 64 } 62 65 63 MockContentFilter::MockContentFilter(const ResourceResponse&)66 void MockContentFilter::responseReceived(const ResourceResponse&) 64 67 { 65 68 maybeDetermineStatus(DecisionPoint::AfterResponse); 66 69 } 67 70 68 void MockContentFilter::addData(const char* data, int length)71 void MockContentFilter::addData(const char*, int) 69 72 { 70 m_replacementData.append(data, length);71 73 maybeDetermineStatus(DecisionPoint::AfterAddData); 72 74 } … … 87 89 } 88 90 89 const char* MockContentFilter::getReplacementData(int& length) const91 Ref<SharedBuffer> MockContentFilter::replacementData() const 90 92 { 91 length = m_replacementData.size();92 return m_replacementData.data();93 ASSERT(didBlockData()); 94 return adoptRef(*SharedBuffer::create(m_replacementData.data(), m_replacementData.size()).leakRef()); 93 95 } 94 96 95 97 ContentFilterUnblockHandler MockContentFilter::unblockHandler() const 96 98 { 99 ASSERT(didBlockData()); 97 100 using DecisionHandlerFunction = ContentFilterUnblockHandler::DecisionHandlerFunction; 98 101 -
trunk/Source/WebCore/testing/MockContentFilter.h
r181791 r182356 33 33 34 34 class MockContentFilter final : public PlatformContentFilter { 35 friend std::unique_ptr<MockContentFilter> std::make_unique<MockContentFilter>( const ResourceResponse&);35 friend std::unique_ptr<MockContentFilter> std::make_unique<MockContentFilter>(); 36 36 37 37 public: 38 38 static void ensureInstalled(); 39 static bool canHandleResponse(const ResourceResponse&);40 static std::unique_ptr<MockContentFilter> create( const ResourceResponse&);39 static bool enabled(); 40 static std::unique_ptr<MockContentFilter> create(); 41 41 42 void responseReceived(const ResourceResponse&) override; 42 43 void addData(const char* data, int length) override; 43 44 void finishedAddingData() override; 44 45 bool needsMoreData() const override; 45 46 bool didBlockData() const override; 46 const char* getReplacementData(int& length) const override;47 Ref<SharedBuffer> replacementData() const override; 47 48 ContentFilterUnblockHandler unblockHandler() const override; 48 49 String unblockRequestDeniedScript() const override; … … 55 56 }; 56 57 57 explicit MockContentFilter(const ResourceResponse&);58 MockContentFilter() = default; 58 59 void maybeDetermineStatus(MockContentFilterSettings::DecisionPoint); 59 60 -
trunk/Source/WebCore/testing/MockContentFilterSettings.cpp
r181791 r182356 29 29 #if ENABLE(CONTENT_FILTERING) 30 30 31 #include "ContentFilter.h" 31 32 #include "ContentFilterUnblockHandler.h" 32 33 #include <mutex> 33 34 #include <wtf/NeverDestroyed.h> 35 #include <wtf/text/StringBuilder.h> 34 36 35 37 namespace WebCore { … … 51 53 static std::once_flag onceFlag; 52 54 std::call_once(onceFlag, [] { 53 unblockRequestURL.construct(ContentFilterUnblockHandler::unblockURLScheme()); 54 unblockRequestURL.get().append("://"); 55 unblockRequestURL.get().append(unblockURLHost()); 55 StringBuilder unblockRequestURLBuilder; 56 unblockRequestURLBuilder.append(ContentFilter::urlScheme()); 57 unblockRequestURLBuilder.append("://"); 58 unblockRequestURLBuilder.append(unblockURLHost()); 59 unblockRequestURL.construct(unblockRequestURLBuilder.toString()); 56 60 }); 57 61 return unblockRequestURL; -
trunk/Source/WebKit2/ChangeLog
r182348 r182356 1 2015-04-04 Andy Estes <aestes@apple.com> 2 3 [Content Filtering] Blocked page is not always displayed when it should be 4 https://bugs.webkit.org/show_bug.cgi?id=143410 5 6 Reviewed by Andreas Kling. 7 8 * UIProcess/WebFrameProxy.cpp: 9 (WebKit::WebFrameProxy::didStartProvisionalLoad): Stopped clearing m_contentFilterUnblockHandler here. 10 (WebKit::WebFrameProxy::didHandleContentFilterUnblockNavigation): Started doing it here instead. 11 1 12 2015-04-04 Chris Dumez <cdumez@apple.com> 2 13 -
trunk/Source/WebKit2/UIProcess/WebFrameProxy.cpp
r181791 r182356 128 128 { 129 129 m_frameLoadState.didStartProvisionalLoad(url); 130 #if ENABLE(CONTENT_FILTERING)131 m_contentFilterUnblockHandler = { };132 #endif133 130 } 134 131 … … 237 234 bool WebFrameProxy::didHandleContentFilterUnblockNavigation(const WebCore::ResourceRequest& request) 238 235 { 239 if (!m_contentFilterUnblockHandler.canHandleRequest(request)) 240 return false; 236 if (!m_contentFilterUnblockHandler.canHandleRequest(request)) { 237 m_contentFilterUnblockHandler = { }; 238 return false; 239 } 241 240 242 241 RefPtr<WebPageProxy> page { m_page };
Note: See TracChangeset
for help on using the changeset viewer.