⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 181523 in webkit


Ignore:
Timestamp:
Mar 15, 2015, 10:44:03 PM (11 years ago)
Author:
aestes@apple.com
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.
Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r181522 r181523  
     12015-03-15  Andy Estes  <aestes@apple.com>
     2
     3        [Content Filtering] Adopt new NEFilterSource SPI
     4        https://bugs.webkit.org/show_bug.cgi?id=142710
     5        rdar://problem/19023855
     6
     7        Reviewed by Dan Bernstein.
     8
     9        Teach NetworkExtensionContentFilter to use a new, alternate NEFilterSource SPI on platforms where it is available.
     10
     11        * platform/ContentFilter.cpp:
     12        (WebCore::ContentFilter::types): Renamed HAVE(NE_FILTER_SOURCE) to HAVE(NETWORK_EXTENSION).
     13        * platform/cocoa/NetworkExtensionContentFilter.h: Renamed member variables to remove redundancy, forward-declared NEFilterSourceStatus,
     14        added a dispatch_semaphore member variable to avoid creating and destroying multiple semaphores, and made m_originalData a SharedBuffer.
     15        * platform/cocoa/NetworkExtensionContentFilter.mm:
     16        (decisionInfoReplacementData): Returned the replacement data from a decision handler info dictionary.
     17        (WebCore::createNEFilterSource): Created either an old-style or new-style NEFilterSource object.
     18        (WebCore::NetworkExtensionContentFilter::NetworkExtensionContentFilter): Called receivedResponse:decisionHandler: when using the new SPI.
     19        (WebCore::NetworkExtensionContentFilter::~NetworkExtensionContentFilter): Released the dispatch_semaphore.
     20        (WebCore::NetworkExtensionContentFilter::addData): Appended the copied NSData to m_originalData, avoiding an additional copy previously
     21        being made by NSMutableData. Used the new receivedData:decisionHandler: SPI when appropriate.
     22        (WebCore::NetworkExtensionContentFilter::finishedAddingData): Used the new finishedLoadingWithDecisionHandler: SPI when appropriate.
     23        (WebCore::NetworkExtensionContentFilter::needsMoreData): Changed m_neFilterSourceStatus to m_status.
     24        (WebCore::NetworkExtensionContentFilter::didBlockData): Ditto.
     25        (WebCore::NetworkExtensionContentFilter::getReplacementData): Returned the replacement data from NEFilterSource if the load was blocked.
     26        Otherwise, returned the original data.
     27        (WebCore::NetworkExtensionContentFilter::handleDecision): Added a helper to set m_status and m_replacementData, and to signal m_semaphore.
     28        * platform/spi/cocoa/NEFilterSourceSPI.h: Declared the new NEFilterSource SPI on platforms that support it.
     29
    1302015-03-15  Brent Fulgham  <bfulgham@apple.com>
    231
  • trunk/Source/WebCore/platform/ContentFilter.cpp

    r181291 r181523  
    4141        Vector<ContentFilter::Type> {
    4242            type<ParentalControlsContentFilter>(),
    43 #if HAVE(NE_FILTER_SOURCE)
     43#if HAVE(NETWORK_EXTENSION)
    4444            type<NetworkExtensionContentFilter>()
    4545#endif
  • trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.h

    r181302 r181523  
    2828
    2929#include "ContentFilter.h"
     30#include "SharedBuffer.h"
     31#include <objc/NSObjCRuntime.h>
    3032#include <wtf/Compiler.h>
     33#include <wtf/OSObjectPtr.h>
     34#include <wtf/Ref.h>
    3135#include <wtf/RetainPtr.h>
    3236
    33 #define HAVE_NE_FILTER_SOURCE TARGET_OS_EMBEDDED || (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 && CPU(X86_64))
     37#define HAVE_NETWORK_EXTENSION PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 && CPU(X86_64))
     38
     39enum NEFilterSourceStatus : NSInteger;
    3440
    3541OBJC_CLASS NEFilterSource;
     42OBJC_CLASS NSData;
     43OBJC_CLASS NSDictionary;
    3644OBJC_CLASS NSMutableData;
    3745
     
    4755    static std::unique_ptr<NetworkExtensionContentFilter> create(const ResourceResponse&);
    4856
    49     ~NetworkExtensionContentFilter() override;
    5057    void addData(const char* data, int length) override;
    5158    void finishedAddingData() override;
     
    5764private:
    5865    explicit NetworkExtensionContentFilter(const ResourceResponse&);
     66    void handleDecision(NEFilterSourceStatus, NSData *replacementData);
    5967
    60     long m_neFilterSourceStatus;
     68    NEFilterSourceStatus m_status;
     69    OSObjectPtr<dispatch_queue_t> m_queue;
     70    OSObjectPtr<dispatch_semaphore_t> m_semaphore;
     71    Ref<SharedBuffer> m_originalData;
     72    RetainPtr<NSData> m_replacementData;
    6173    RetainPtr<NEFilterSource> m_neFilterSource;
    62     dispatch_queue_t m_neFilterSourceQueue;
    63     RetainPtr<NSMutableData> m_originalData;
    6474};
    6575
  • trunk/Source/WebCore/platform/cocoa/NetworkExtensionContentFilter.mm

    r181037 r181523  
    2727#import "NetworkExtensionContentFilter.h"
    2828
    29 #if HAVE(NE_FILTER_SOURCE)
     29#if HAVE(NETWORK_EXTENSION)
    3030
    3131#import "NEFilterSourceSPI.h"
     
    3636SOFT_LINK_FRAMEWORK(NetworkExtension);
    3737SOFT_LINK_CLASS(NetworkExtension, NEFilterSource);
     38
     39#if HAVE(MODERN_NE_FILTER_SOURCE)
     40// FIXME: <rdar://problem/20165664> Expose decisionHandler dictionary keys as NSString constants in NEFilterSource.h
     41static NSString * const optionsPageData = @"PageData";
     42
     43static inline NSData *replacementDataFromDecisionInfo(NSDictionary *decisionInfo)
     44{
     45    id replacementData = decisionInfo[optionsPageData];
     46    ASSERT(!replacementData || [replacementData isKindOfClass:[NSData class]]);
     47    return replacementData;
     48}
     49#endif
    3850
    3951namespace WebCore {
     
    4961}
    5062
     63static 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
    5174NetworkExtensionContentFilter::NetworkExtensionContentFilter(const ResourceResponse& response)
    52     : m_neFilterSourceStatus { NEFilterSourceStatusNeedsMoreData }
    53     , m_neFilterSource { adoptNS([allocNEFilterSourceInstance() initWithURL:[response.nsURLResponse() URL] direction:NEFilterSourceDirectionInbound socketIdentifier:0]) }
    54     , m_neFilterSourceQueue { dispatch_queue_create("com.apple.WebCore.NEFilterSourceQueue", DISPATCH_QUEUE_SERIAL) }
     75    : m_status { NEFilterSourceStatusNeedsMoreData }
     76    , m_queue { adoptOSObject(dispatch_queue_create("com.apple.WebCore.NEFilterSourceQueue", DISPATCH_QUEUE_SERIAL)) }
     77    , m_semaphore { adoptOSObject(dispatch_semaphore_create(0)) }
     78    , m_originalData { *SharedBuffer::create() }
     79    , m_neFilterSource { createNEFilterSource(response.url(), m_queue.get()) }
    5580{
    5681    ASSERT([getNEFilterSourceClass() filterRequired]);
    5782
    58     long long expectedContentSize = [response.nsURLResponse() expectedContentLength];
    59     if (expectedContentSize < 0)
    60         m_originalData = adoptNS([[NSMutableData alloc] init]);
    61     else
    62         m_originalData = adoptNS([[NSMutableData alloc] initWithCapacity:(NSUInteger)expectedContentSize]);
    63 }
    64 
    65 NetworkExtensionContentFilter::~NetworkExtensionContentFilter()
    66 {
    67     dispatch_release(m_neFilterSourceQueue);
    68 }
    69 
    70 void NetworkExtensionContentFilter::addData(const char* data, int length)
    71 {
    72     // FIXME: NEFilterSource doesn't buffer data like WebFilterEvaluator does,
    73     // so we need to do it ourselves so getReplacementData() can return the
    74     // original bytes back to the loader. We should find a way to remove this
    75     // additional copy.
    76     [m_originalData appendBytes:data length:length];
    77 
    78     dispatch_semaphore_t neFilterSourceSemaphore = dispatch_semaphore_create(0);
    79     [m_neFilterSource addData:[NSData dataWithBytes:(void*)data length:length] withCompletionQueue:m_neFilterSourceQueue completionHandler:^(NEFilterSourceStatus status, NSData *) {
    80         m_neFilterSourceStatus = status;
    81         dispatch_semaphore_signal(neFilterSourceSemaphore);
     83#if HAVE(MODERN_NE_FILTER_SOURCE)
     84    [m_neFilterSource receivedResponse:response.nsURLResponse() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
     85        handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
    8286    }];
    8387
     
    8589    // blocked/not blocked answer from the filter immediately after calling
    8690    // addData(). We should find a way to make this asynchronous.
    87     dispatch_semaphore_wait(neFilterSourceSemaphore, DISPATCH_TIME_FOREVER);
    88     dispatch_release(neFilterSourceSemaphore);
     91    dispatch_semaphore_wait(m_semaphore.get(), DISPATCH_TIME_FOREVER);
     92#endif
     93}
     94
     95void NetworkExtensionContentFilter::addData(const char* data, int length)
     96{
     97    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 the
     101    // original bytes back to the loader. We should find a way to remove this
     102    // additional copy.
     103    m_originalData->append((CFDataRef)copiedData.get());
     104
     105#if HAVE(MODERN_NE_FILTER_SOURCE)
     106    [m_neFilterSource receivedData:copiedData.get() decisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
     107        handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
     108    }];
     109#else
     110    [m_neFilterSource addData:copiedData.get() withCompletionQueue:m_queue.get() completionHandler:[this](NEFilterSourceStatus status, NSData *replacementData) {
     111        ASSERT(!replacementData);
     112        handleDecision(status, replacementData);
     113    }];
     114#endif
     115
     116    // FIXME: We have to block here since DocumentLoader expects to have a
     117    // blocked/not blocked answer from the filter immediately after calling
     118    // addData(). We should find a way to make this asynchronous.
     119    dispatch_semaphore_wait(m_semaphore.get(), DISPATCH_TIME_FOREVER);
    89120}
    90121
    91122void NetworkExtensionContentFilter::finishedAddingData()
    92123{
    93     dispatch_semaphore_t neFilterSourceSemaphore = dispatch_semaphore_create(0);
    94     [m_neFilterSource dataCompleteWithCompletionQueue:m_neFilterSourceQueue completionHandler:^(NEFilterSourceStatus status, NSData *) {
    95         m_neFilterSourceStatus = status;
    96         dispatch_semaphore_signal(neFilterSourceSemaphore);
     124#if HAVE(MODERN_NE_FILTER_SOURCE)
     125    [m_neFilterSource finishedLoadingWithDecisionHandler:[this](NEFilterSourceStatus status, NSDictionary *decisionInfo) {
     126        handleDecision(status, replacementDataFromDecisionInfo(decisionInfo));
    97127    }];
     128#else
     129    [m_neFilterSource dataCompleteWithCompletionQueue:m_queue.get() completionHandler:[this](NEFilterSourceStatus status, NSData *replacementData) {
     130        ASSERT(!replacementData);
     131        handleDecision(status, replacementData);
     132    }];
     133#endif
    98134
    99135    // FIXME: We have to block here since DocumentLoader expects to have a
    100136    // blocked/not blocked answer from the filter immediately after calling
    101137    // finishedAddingData(). We should find a way to make this asynchronous.
    102     dispatch_semaphore_wait(neFilterSourceSemaphore, DISPATCH_TIME_FOREVER);
    103     dispatch_release(neFilterSourceSemaphore);
     138    dispatch_semaphore_wait(m_semaphore.get(), DISPATCH_TIME_FOREVER);
    104139}
    105140
    106141bool NetworkExtensionContentFilter::needsMoreData() const
    107142{
    108     return m_neFilterSourceStatus == NEFilterSourceStatusNeedsMoreData;
     143    return m_status == NEFilterSourceStatusNeedsMoreData;
    109144}
    110145
    111146bool NetworkExtensionContentFilter::didBlockData() const
    112147{
    113     return m_neFilterSourceStatus == NEFilterSourceStatusBlock;
     148    return m_status == NEFilterSourceStatusBlock;
    114149}
    115150
     
    117152{
    118153    if (didBlockData()) {
    119         length = 0;
    120         return nullptr;
     154        length = [m_replacementData length];
     155        return static_cast<const char*>([m_replacementData bytes]);
    121156    }
    122157
    123     length = [m_originalData length];
    124     return static_cast<const char*>([m_originalData bytes]);
     158    length = m_originalData->size();
     159    return m_originalData->data();
    125160}
    126161
     
    130165}
    131166
     167void NetworkExtensionContentFilter::handleDecision(NEFilterSourceStatus status, NSData *replacementData)
     168{
     169    m_status = status;
     170    if (status == NEFilterSourceStatusBlock)
     171        m_replacementData = replacementData;
     172    dispatch_semaphore_signal(m_semaphore.get());
     173}
     174
    132175} // namespace WebCore
    133176
    134 #endif // HAVE(NE_FILTER_SOURCE)
     177#endif // HAVE(NETWORK_EXTENSION)
  • trunk/Source/WebCore/platform/spi/cocoa/NEFilterSourceSPI.h

    r180708 r181523  
    2424 */
    2525
     26#define HAVE_MODERN_NE_FILTER_SOURCE (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000)
     27
    2628#if USE(APPLE_INTERNAL_SDK)
    2729
     
    4547@end
    4648
    47 @interface NEFilterSource (Details)
     49@interface NEFilterSource (WKLegacyDetails)
    4850+ (BOOL)filterRequired;
    4951- (id)initWithURL:(NSURL *)url direction:(NEFilterSourceDirection)direction socketIdentifier:(uint64_t)socketIdentifier;
     
    5658@end
    5759
     60#if HAVE(MODERN_NE_FILTER_SOURCE)
     61typedef void (^NEFilterSourceDecisionHandler)(NEFilterSourceStatus, NSDictionary *);
     62
     63@interface NEFilterSource (WKModernDetails)
     64- (id)initWithDecisionQueue:(dispatch_queue_t)queue;
     65- (void)willSendRequest:(NSURLRequest *)request decisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
     66- (void)receivedResponse:(NSURLResponse *)response decisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
     67- (void)receivedData:(NSData *)data decisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
     68- (void)finishedLoadingWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
     69- (void)remediateWithDecisionHandler:(NEFilterSourceDecisionHandler)decisionHandler;
     70@end
    5871#endif
     72
     73#endif
Note: See TracChangeset for help on using the changeset viewer.