- Revision
- 181523
- Author
- aes...@apple.com
- Date
- 2015-03-15 22:44:03 -0700 (Sun, 15 Mar 2015)
Log Message
[Content Filtering] Adopt new NEFilterSource SPI
https://bugs.webkit.org/show_bug.cgi?id=142710
rdar://problem/19023855
Reviewed by Dan Bernstein.
Teach NetworkExtensionContentFilter to use a new, alternate NEFilterSource SPI on platforms where it is available.
* platform/ContentFilter.cpp:
(WebCore::ContentFilter::types): Renamed HAVE(NE_FILTER_SOURCE) to HAVE(NETWORK_EXTENSION).
* platform/cocoa/NetworkExtensionContentFilter.h: Renamed member variables to remove redundancy, forward-declared NEFilterSourceStatus,
added a dispatch_semaphore member variable to avoid creating and destroying multiple semaphores, and made m_originalData a SharedBuffer.
* platform/cocoa/NetworkExtensionContentFilter.mm:
(decisionInfoReplacementData): Returned the replacement data from a decision handler info dictionary.
(WebCore::createNEFilterSource): Created either an old-style or new-style NEFilterSource object.
(WebCore::NetworkExtensionContentFilter::NetworkExtensionContentFilter): Called receivedResponse:decisionHandler: when using the new SPI.
(WebCore::NetworkExtensionContentFilter::~NetworkExtensionContentFilter): Released the dispatch_semaphore.
(WebCore::NetworkExtensionContentFilter::addData): Appended the copied NSData to m_originalData, avoiding an additional copy previously
being made by NSMutableData. Used the new receivedData:decisionHandler: SPI when appropriate.
(WebCore::NetworkExtensionContentFilter::finishedAddingData): Used the new finishedLoadingWithDecisionHandler: SPI when appropriate.
(WebCore::NetworkExtensionContentFilter::needsMoreData): Changed m_neFilterSourceStatus to m_status.
(WebCore::NetworkExtensionContentFilter::didBlockData): Ditto.
(WebCore::NetworkExtensionContentFilter::getReplacementData): Returned the replacement data from NEFilterSource if the load was blocked.
Otherwise, returned the original data.
(WebCore::NetworkExtensionContentFilter::handleDecision): Added a helper to set m_status and m_replacementData, and to signal m_semaphore.
* platform/spi/cocoa/NEFilterSourceSPI.h: Declared the new NEFilterSource SPI on platforms that support it.
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (181522 => 181523)
--- trunk/Source/WebCore/ChangeLog 2015-03-16 05:34:27 UTC (rev 181522)
+++ trunk/Source/WebCore/ChangeLog 2015-03-16 05:44:03 UTC (rev 181523)
@@ -1,3 +1,32 @@
+2015-03-15 Andy Estes <aes...@apple.com>
+
+ [Content Filtering] Adopt new NEFilterSource SPI
+ https://bugs.webkit.org/show_bug.cgi?id=142710
+ rdar://problem/19023855
+
+ Reviewed by Dan Bernstein.
+
+ Teach NetworkExtensionContentFilter to use a new, alternate NEFilterSource SPI on platforms where it is available.
+
+ * platform/ContentFilter.cpp:
+ (WebCore::ContentFilter::types): Renamed HAVE(NE_FILTER_SOURCE) to HAVE(NETWORK_EXTENSION).
+ * platform/cocoa/NetworkExtensionContentFilter.h: Renamed member variables to remove redundancy, forward-declared NEFilterSourceStatus,
+ added a dispatch_semaphore member variable to avoid creating and destroying multiple semaphores, and made m_originalData a SharedBuffer.
+ * platform/cocoa/NetworkExtensionContentFilter.mm:
+ (decisionInfoReplacementData): Returned the replacement data from a decision handler info dictionary.
+ (WebCore::createNEFilterSource): Created either an old-style or new-style NEFilterSource object.
+ (WebCore::NetworkExtensionContentFilter::NetworkExtensionContentFilter): Called receivedResponse:decisionHandler: when using the new SPI.
+ (WebCore::NetworkExtensionContentFilter::~NetworkExtensionContentFilter): Released the dispatch_semaphore.
+ (WebCore::NetworkExtensionContentFilter::addData): Appended the copied NSData to m_originalData, avoiding an additional copy previously
+ being made by NSMutableData. Used the new receivedData:decisionHandler: SPI when appropriate.
+ (WebCore::NetworkExtensionContentFilter::finishedAddingData): Used the new finishedLoadingWithDecisionHandler: SPI when appropriate.
+ (WebCore::NetworkExtensionContentFilter::needsMoreData): Changed m_neFilterSourceStatus to m_status.
+ (WebCore::NetworkExtensionContentFilter::didBlockData): Ditto.
+ (WebCore::NetworkExtensionContentFilter::getReplacementData): Returned the replacement data from NEFilterSource if the load was blocked.
+ Otherwise, returned the original data.
+ (WebCore::NetworkExtensionContentFilter::handleDecision): Added a helper to set m_status and m_replacementData, and to signal m_semaphore.
+ * platform/spi/cocoa/NEFilterSourceSPI.h: Declared the new NEFilterSource SPI on platforms that support it.
+
2015-03-15 Brent Fulgham <bfulg...@apple.com>
Scroll snap points are not supported on iframe content
Modified: trunk/Source/WebCore/platform/ContentFilter.cpp (181522 => 181523)
--- trunk/Source/WebCore/platform/ContentFilter.cpp 2015-03-16 05:34:27 UTC (rev 181522)
+++ trunk/Source/WebCore/platform/ContentFilter.cpp 2015-03-16 05:44:03 UTC (rev 181523)
@@ -40,7 +40,7 @@
static NeverDestroyed<Vector<ContentFilter::Type>> types {
Vector<ContentFilter::Type> {
type<ParentalControlsContentFilter>(),
-#if HAVE(NE_FILTER_SOURCE)
+#if HAVE(NETWORK_EXTENSION)
type<NetworkExtensionContentFilter>()
#endif
}
Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h (181522 => 181523)
--- trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h 2015-03-16 05:34:27 UTC (rev 181522)
+++ trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h 2015-03-16 05:44:03 UTC (rev 181523)
@@ -27,12 +27,20 @@
#define NetworkExtensionContentFilter_h
#include "ContentFilter.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_NE_FILTER_SOURCE TARGET_OS_EMBEDDED || (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 && CPU(X86_64))
+#define HAVE_NETWORK_EXTENSION PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 && CPU(X86_64))
+enum NEFilterSourceStatus : NSInteger;
+
OBJC_CLASS NEFilterSource;
+OBJC_CLASS NSData;
+OBJC_CLASS NSDictionary;
OBJC_CLASS NSMutableData;
namespace WebCore {
@@ -46,7 +54,6 @@
static bool canHandleResponse(const ResourceResponse&);
static std::unique_ptr<NetworkExtensionContentFilter> create(const ResourceResponse&);
- ~NetworkExtensionContentFilter() override;
void addData(const char* data, int length) override;
void finishedAddingData() override;
bool needsMoreData() const override;
@@ -56,11 +63,14 @@
private:
explicit NetworkExtensionContentFilter(const ResourceResponse&);
+ void handleDecision(NEFilterSourceStatus, NSData *replacementData);
- long m_neFilterSourceStatus;
+ 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;
- dispatch_queue_t m_neFilterSourceQueue;
- RetainPtr<NSMutableData> m_originalData;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm (181522 => 181523)
--- trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm 2015-03-16 05:34:27 UTC (rev 181522)
+++ trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm 2015-03-16 05:44:03 UTC (rev 181523)
@@ -26,7 +26,7 @@
#import "config.h"
#import "NetworkExtensionContentFilter.h"
-#if HAVE(NE_FILTER_SOURCE)
+#if HAVE(NETWORK_EXTENSION)
#import "NEFilterSourceSPI.h"
#import "ResourceResponse.h"
@@ -36,6 +36,18 @@
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];
+ ASSERT(!replacementData || [replacementData isKindOfClass:[NSData class]]);
+ return replacementData;
+}
+#endif
+
namespace WebCore {
bool NetworkExtensionContentFilter::canHandleResponse(const ResourceResponse& response)
@@ -48,80 +60,103 @@
return std::make_unique<NetworkExtensionContentFilter>(response);
}
+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)
- : m_neFilterSourceStatus { NEFilterSourceStatusNeedsMoreData }
- , m_neFilterSource { adoptNS([allocNEFilterSourceInstance() initWithURL:[response.nsURLResponse() URL] direction:NEFilterSourceDirectionInbound socketIdentifier:0]) }
- , m_neFilterSourceQueue { dispatch_queue_create("com.apple.WebCore.NEFilterSourceQueue", DISPATCH_QUEUE_SERIAL) }
+ : 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()) }
{
ASSERT([getNEFilterSourceClass() filterRequired]);
- long long expectedContentSize = [response.nsURLResponse() expectedContentLength];
- if (expectedContentSize < 0)
- m_originalData = adoptNS([[NSMutableData alloc] init]);
- else
- m_originalData = adoptNS([[NSMutableData alloc] initWithCapacity:(NSUInteger)expectedContentSize]);
-}
+#if HAVE(MODERN_NE_FILTER_SOURCE)
+ [m_neFilterSource receivedResponse:response.nsURLResponse() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
+ handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
+ }];
-NetworkExtensionContentFilter::~NetworkExtensionContentFilter()
-{
- dispatch_release(m_neFilterSourceQueue);
+ // FIXME: We have to block here since DocumentLoader expects to have a
+ // blocked/not blocked answer from the filter immediately after calling
+ // addData(). We should find a way to make this asynchronous.
+ dispatch_semaphore_wait(m_semaphore.get(), DISPATCH_TIME_FOREVER);
+#endif
}
void NetworkExtensionContentFilter::addData(const char* data, int length)
{
+ 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 appendBytes:data length:length];
+ m_originalData->append((CFDataRef)copiedData.get());
- dispatch_semaphore_t neFilterSourceSemaphore = dispatch_semaphore_create(0);
- [m_neFilterSource addData:[NSData dataWithBytes:(void*)data length:length] withCompletionQueue:m_neFilterSourceQueue completionHandler:^(NEFilterSourceStatus status, NSData *) {
- m_neFilterSourceStatus = status;
- dispatch_semaphore_signal(neFilterSourceSemaphore);
+#if HAVE(MODERN_NE_FILTER_SOURCE)
+ [m_neFilterSource receivedData:copiedData.get() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
+ handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
}];
+#else
+ [m_neFilterSource addData:copiedData.get() withCompletionQueue:m_queue.get() completionHandler:[this](NEFilterSourceStatus status, NSData *replacementData) {
+ ASSERT(!replacementData);
+ handleDecision(status, replacementData);
+ }];
+#endif
// FIXME: We have to block here since DocumentLoader expects to have a
// blocked/not blocked answer from the filter immediately after calling
// addData(). We should find a way to make this asynchronous.
- dispatch_semaphore_wait(neFilterSourceSemaphore, DISPATCH_TIME_FOREVER);
- dispatch_release(neFilterSourceSemaphore);
+ dispatch_semaphore_wait(m_semaphore.get(), DISPATCH_TIME_FOREVER);
}
void NetworkExtensionContentFilter::finishedAddingData()
{
- dispatch_semaphore_t neFilterSourceSemaphore = dispatch_semaphore_create(0);
- [m_neFilterSource dataCompleteWithCompletionQueue:m_neFilterSourceQueue completionHandler:^(NEFilterSourceStatus status, NSData *) {
- m_neFilterSourceStatus = status;
- dispatch_semaphore_signal(neFilterSourceSemaphore);
+#if HAVE(MODERN_NE_FILTER_SOURCE)
+ [m_neFilterSource finishedLoadingWithDecisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
+ handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
}];
+#else
+ [m_neFilterSource dataCompleteWithCompletionQueue:m_queue.get() completionHandler:[this](NEFilterSourceStatus status, NSData *replacementData) {
+ ASSERT(!replacementData);
+ handleDecision(status, replacementData);
+ }];
+#endif
// FIXME: We have to block here since DocumentLoader expects to have a
// blocked/not blocked answer from the filter immediately after calling
// finishedAddingData(). We should find a way to make this asynchronous.
- dispatch_semaphore_wait(neFilterSourceSemaphore, DISPATCH_TIME_FOREVER);
- dispatch_release(neFilterSourceSemaphore);
+ dispatch_semaphore_wait(m_semaphore.get(), DISPATCH_TIME_FOREVER);
}
bool NetworkExtensionContentFilter::needsMoreData() const
{
- return m_neFilterSourceStatus == NEFilterSourceStatusNeedsMoreData;
+ return m_status == NEFilterSourceStatusNeedsMoreData;
}
bool NetworkExtensionContentFilter::didBlockData() const
{
- return m_neFilterSourceStatus == NEFilterSourceStatusBlock;
+ return m_status == NEFilterSourceStatusBlock;
}
const char* NetworkExtensionContentFilter::getReplacementData(int& length) const
{
if (didBlockData()) {
- length = 0;
- return nullptr;
+ length = [m_replacementData length];
+ return static_cast<const char*>([m_replacementData bytes]);
}
- length = [m_originalData length];
- return static_cast<const char*>([m_originalData bytes]);
+ length = m_originalData->size();
+ return m_originalData->data();
}
ContentFilterUnblockHandler NetworkExtensionContentFilter::unblockHandler() const
@@ -129,6 +164,14 @@
return { };
}
+void NetworkExtensionContentFilter::handleDecision(NEFilterSourceStatus status, NSData *replacementData)
+{
+ m_status = status;
+ if (status == NEFilterSourceStatusBlock)
+ m_replacementData = replacementData;
+ dispatch_semaphore_signal(m_semaphore.get());
+}
+
} // namespace WebCore
-#endif // HAVE(NE_FILTER_SOURCE)
+#endif // HAVE(NETWORK_EXTENSION)
Modified: trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h (181522 => 181523)
--- trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h 2015-03-16 05:34:27 UTC (rev 181522)
+++ trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h 2015-03-16 05:44:03 UTC (rev 181523)
@@ -23,6 +23,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define HAVE_MODERN_NE_FILTER_SOURCE (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000)
+
#if USE(APPLE_INTERNAL_SDK)
#import <NetworkExtension/NEFilterSource.h>
@@ -44,7 +46,7 @@
@interface NEFilterSource : NSObject
@end
-@interface NEFilterSource (Details)
+@interface NEFilterSource (WKLegacyDetails)
+ (BOOL)filterRequired;
- (id)initWithURL:(NSURL *)url direction:(NEFilterSourceDirection)direction socketIdentifier:(uint64_t)socketIdentifier;
- (void)addData:(NSData *)data withCompletionQueue:(dispatch_queue_t)queue completionHandler:(void (^)(NEFilterSourceStatus, NSData *))completionHandler;
@@ -55,4 +57,17 @@
@property (readonly) uint64_t socketIdentifier;
@end
+#if HAVE(MODERN_NE_FILTER_SOURCE)
+typedef void (^NEFilterSourceDecisionHandler)(NEFilterSourceStatus, NSDictionary *);
+
+@interface NEFilterSource (WKModernDetails)
+- (id)initWithDecisionQueue:(dispatch_queue_t)queue;
+- (void)willSendRequest:(NSURLRequest *)request decisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
+- (void)receivedResponse:(NSURLResponse *)response decisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
+- (void)receivedData:(NSData *)data decisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
+- (void)finishedLoadingWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
+- (void)remediateWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
+@end
#endif
+
+#endif