Changeset 213988 in webkit


Ignore:
Timestamp:
Mar 15, 2017 10:59:08 AM (7 years ago)
Author:
achristensen@apple.com
Message:

Compiled content extensions should include the JSON source
https://bugs.webkit.org/show_bug.cgi?id=169643

Reviewed by Geoffrey Garen.

Source/WebCore:

Serializing the JSON string from which a content extension was compiled
to disk with the compiled content extension will allow us to validate content
extensions and automatically migrate older content extensions to new versions.
It less than doubles the size of the compiled content extension on disk, and when
interpreting the bytecode that memory is never read, so it doesn't increase our
dirty memory usage.

Covered by new API tests.

  • contentextensions/ContentExtensionCompiler.cpp:

(WebCore::ContentExtensions::compileRuleList):

  • contentextensions/ContentExtensionCompiler.h:

Source/WebKit2:

  • UIProcess/API/APIContentExtensionStore.cpp:

(API::ContentExtensionStore::ContentExtensionStore):
(API::ContentExtensionMetaData::fileSize):
(API::encodeContentExtensionMetaData):
(API::decodeContentExtensionMetaData):
(API::compiledToFile):
(API::createExtension):
(API::ContentExtensionStore::getContentExtensionSource):

  • UIProcess/API/APIContentExtensionStore.h:
  • UIProcess/API/Cocoa/WKContentExtensionStore.mm:

(toWKErrorCode):
(-[WKContentExtensionStore lookupContentExtensionForIdentifier:completionHandler:]):
(-[WKContentExtensionStore removeContentExtensionForIdentifier:completionHandler:]):
(-[WKContentExtensionStore _getContentExtensionSourceForIdentifier:completionHandler:]):

  • UIProcess/API/Cocoa/WKContentExtensionStorePrivate.h:
  • UIProcess/API/Cocoa/WKError.h:
  • UIProcess/API/Cocoa/_WKUserContentExtensionStore.h:
  • UIProcess/API/Cocoa/_WKUserContentExtensionStore.mm:

(toUserContentExtensionStoreError):
(-[_WKUserContentExtensionStore compileContentExtensionForIdentifier:encodedContentExtension:completionHandler:]):
(-[_WKUserContentExtensionStore lookupContentExtensionForIdentifier:completionHandler:]):
(-[_WKUserContentExtensionStore removeContentExtensionForIdentifier:completionHandler:]):

Tools:

  • TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
  • TestWebKitAPI/Tests/WebKit2Cocoa/WKUserContentExtensionStore.mm:

(TEST_F):

Location:
trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r213987 r213988  
     12017-03-15  Alex Christensen  <achristensen@webkit.org>
     2
     3        Compiled content extensions should include the JSON source
     4        https://bugs.webkit.org/show_bug.cgi?id=169643
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Serializing the JSON string from which a content extension was compiled
     9        to disk with the compiled content extension will allow us to validate content
     10        extensions and automatically migrate older content extensions to new versions.
     11        It less than doubles the size of the compiled content extension on disk, and when
     12        interpreting the bytecode that memory is never read, so it doesn't increase our
     13        dirty memory usage.
     14
     15        Covered by new API tests.
     16
     17        * contentextensions/ContentExtensionCompiler.cpp:
     18        (WebCore::ContentExtensions::compileRuleList):
     19        * contentextensions/ContentExtensionCompiler.h:
     20
    1212017-03-15  Antoine Quint  <graouts@apple.com>
    222
  • trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp

    r213669 r213988  
    307307    double patternPartitioningStart = monotonicallyIncreasingTime();
    308308#endif
     309   
     310    client.writeSource(ruleJSON);
    309311
    310312    Vector<SerializedActionByte> actions;
  • trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.h

    r213669 r213988  
    4141   
    4242    // Functions should be called in this order. All except writeActions and finalize can be called multiple times, though.
     43    virtual void writeSource(const String&) = 0;
    4344    virtual void writeActions(Vector<SerializedActionByte>&&, bool conditionsApplyOnlyToDomain) = 0;
    4445    virtual void writeFiltersWithoutConditionsBytecode(Vector<DFABytecode>&&) = 0;
  • trunk/Source/WebKit2/ChangeLog

    r213978 r213988  
     12017-03-15  Alex Christensen  <achristensen@webkit.org>
     2
     3        Compiled content extensions should include the JSON source
     4        https://bugs.webkit.org/show_bug.cgi?id=169643
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * UIProcess/API/APIContentExtensionStore.cpp:
     9        (API::ContentExtensionStore::ContentExtensionStore):
     10        (API::ContentExtensionMetaData::fileSize):
     11        (API::encodeContentExtensionMetaData):
     12        (API::decodeContentExtensionMetaData):
     13        (API::compiledToFile):
     14        (API::createExtension):
     15        (API::ContentExtensionStore::getContentExtensionSource):
     16        * UIProcess/API/APIContentExtensionStore.h:
     17        * UIProcess/API/Cocoa/WKContentExtensionStore.mm:
     18        (toWKErrorCode):
     19        (-[WKContentExtensionStore lookupContentExtensionForIdentifier:completionHandler:]):
     20        (-[WKContentExtensionStore removeContentExtensionForIdentifier:completionHandler:]):
     21        (-[WKContentExtensionStore _getContentExtensionSourceForIdentifier:completionHandler:]):
     22        * UIProcess/API/Cocoa/WKContentExtensionStorePrivate.h:
     23        * UIProcess/API/Cocoa/WKError.h:
     24        * UIProcess/API/Cocoa/_WKUserContentExtensionStore.h:
     25        * UIProcess/API/Cocoa/_WKUserContentExtensionStore.mm:
     26        (toUserContentExtensionStoreError):
     27        (-[_WKUserContentExtensionStore compileContentExtensionForIdentifier:encodedContentExtension:completionHandler:]):
     28        (-[_WKUserContentExtensionStore lookupContentExtensionForIdentifier:completionHandler:]):
     29        (-[_WKUserContentExtensionStore removeContentExtensionForIdentifier:completionHandler:]):
     30
    1312017-03-15  Dean Jackson  <dino@apple.com>
    232
  • trunk/Source/WebKit2/UIProcess/API/APIContentExtensionStore.cpp

    r213696 r213988  
    6969    , m_removeQueue(WorkQueue::create("ContentExtensionStore Remove Queue"))
    7070{
     71    WebCore::makeAllDirectories(storePath);
    7172}
    7273
     
    8283// The size and offset of the densely packed bytes in the file, not sizeof and offsetof, which would
    8384// represent the size and offset of the structure in memory, possibly with compiler-added padding.
    84 const size_t ContentExtensionFileHeaderSize = 2 * sizeof(uint32_t) + 4 * sizeof(uint64_t);
    85 const size_t ConditionsApplyOnlyToDomainOffset = sizeof(uint32_t) + 4 * sizeof(uint64_t);
     85const size_t ContentExtensionFileHeaderSize = 2 * sizeof(uint32_t) + 5 * sizeof(uint64_t);
     86const size_t ConditionsApplyOnlyToDomainOffset = sizeof(uint32_t) + 5 * sizeof(uint64_t);
    8687
    8788struct ContentExtensionMetaData {
    8889    uint32_t version { ContentExtensionStore::CurrentContentExtensionFileVersion };
     90    uint64_t sourceSize { 0 };
    8991    uint64_t actionsSize { 0 };
    9092    uint64_t filtersWithoutConditionsBytecodeSize { 0 };
     
    9698    {
    9799        return ContentExtensionFileHeaderSize
     100            + sourceSize
    98101            + actionsSize
    99102            + filtersWithoutConditionsBytecodeSize
     
    108111
    109112    encoder << metaData.version;
     113    encoder << metaData.sourceSize;
    110114    encoder << metaData.actionsSize;
    111115    encoder << metaData.filtersWithoutConditionsBytecodeSize;
     
    130134        if (!decoder.decode(metaData.version))
    131135            return false;
     136        if (!decoder.decode(metaData.sourceSize))
     137            return false;
    132138        if (!decoder.decode(metaData.actionsSize))
    133139            return false;
     
    182188            , m_metaData(metaData)
    183189        {
     190            ASSERT(!metaData.sourceSize);
    184191            ASSERT(!metaData.actionsSize);
    185192            ASSERT(!metaData.filtersWithoutConditionsBytecodeSize);
     
    187194            ASSERT(!metaData.conditionedFiltersBytecodeSize);
    188195            ASSERT(!metaData.conditionsApplyOnlyToDomain);
     196        }
     197       
     198        void writeSource(const String& sourceJSON) final {
     199            ASSERT(!m_filtersWithoutConditionsBytecodeWritten);
     200            ASSERT(!m_filtersWithConditionBytecodeWritten);
     201            ASSERT(!m_conditionFiltersBytecodeWritten);
     202            ASSERT(!m_actionsWritten);
     203            ASSERT(!m_sourceWritten);
     204            writeToFile(sourceJSON.is8Bit());
     205            m_sourceWritten += sizeof(bool);
     206            if (sourceJSON.is8Bit()) {
     207                size_t serializedLength = sourceJSON.length() * sizeof(LChar);
     208                writeToFile(Data(sourceJSON.characters8(), serializedLength));
     209                m_sourceWritten += serializedLength;
     210            } else {
     211                size_t serializedLength = sourceJSON.length() * sizeof(UChar);
     212                writeToFile(Data(reinterpret_cast<const uint8_t*>(sourceJSON.characters16()), serializedLength));
     213                m_sourceWritten += serializedLength;
     214            }
    189215        }
    190216       
     
    223249        void finalize() final
    224250        {
     251            m_metaData.sourceSize = m_sourceWritten;
    225252            m_metaData.actionsSize = m_actionsWritten;
    226253            m_metaData.filtersWithoutConditionsBytecodeSize = m_filtersWithoutConditionsBytecodeWritten;
     
    240267
    241268    private:
     269        void writeToFile(bool value)
     270        {
     271            writeToFile(Data(reinterpret_cast<const uint8_t*>(&value), sizeof(value)));
     272        }
    242273        void writeToFile(const Data& data)
    243274        {
     
    254285        size_t m_conditionFiltersBytecodeWritten { 0 };
    255286        size_t m_actionsWritten { 0 };
     287        size_t m_sourceWritten { 0 };
    256288        bool m_conditionsApplyOnlyToDomain { false };
    257289        bool m_fileError { false };
     
    295327{
    296328    auto sharedMemory = WebKit::SharedMemory::create(const_cast<uint8_t*>(fileData.data()), fileData.size(), WebKit::SharedMemory::Protection::ReadOnly);
     329    const size_t headerAndSourceSize = ContentExtensionFileHeaderSize + metaData.sourceSize;
    297330    auto compiledContentExtensionData = WebKit::WebCompiledContentExtensionData(
    298331        WTFMove(sharedMemory),
    299332        fileData,
    300333        ConditionsApplyOnlyToDomainOffset,
    301         ContentExtensionFileHeaderSize,
     334        headerAndSourceSize,
    302335        metaData.actionsSize,
    303         ContentExtensionFileHeaderSize
     336        headerAndSourceSize
    304337            + metaData.actionsSize,
    305338        metaData.filtersWithoutConditionsBytecodeSize,
    306         ContentExtensionFileHeaderSize
     339        headerAndSourceSize
    307340            + metaData.actionsSize
    308341            + metaData.filtersWithoutConditionsBytecodeSize,
    309342        metaData.filtersWithConditionsBytecodeSize,
    310         ContentExtensionFileHeaderSize
     343        headerAndSourceSize
    311344            + metaData.actionsSize
    312345            + metaData.filtersWithoutConditionsBytecodeSize
     
    402435    WebCore::closeFile(file);
    403436}
    404    
     437
     438void ContentExtensionStore::getContentExtensionSource(const WTF::String& identifier, Function<void(WTF::String)> completionHandler)
     439{
     440    m_readQueue->dispatch([protectedThis = makeRef(*this), identifier = identifier.isolatedCopy(), storePath = m_storePath.isolatedCopy(), completionHandler = WTFMove(completionHandler)]() mutable {
     441        auto path = constructedPath(storePath, identifier);
     442       
     443        auto complete = [protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler)](String source) mutable {
     444            RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), source = source.isolatedCopy()] {
     445                completionHandler(source);
     446            });
     447        };
     448       
     449        ContentExtensionMetaData metaData;
     450        Data fileData;
     451        if (!openAndMapContentExtension(path, metaData, fileData)) {
     452            complete({ });
     453            return;
     454        }
     455       
     456        switch (metaData.version) {
     457        case 9:
     458            if (!metaData.sourceSize) {
     459                complete({ });
     460                return;
     461            }
     462            bool is8Bit = fileData.data()[ContentExtensionFileHeaderSize];
     463            size_t start = ContentExtensionFileHeaderSize + sizeof(bool);
     464            size_t length = metaData.sourceSize - sizeof(bool);
     465            if (is8Bit)
     466                complete(String(fileData.data() + start, length));
     467            else {
     468                ASSERT(!(length % sizeof(UChar)));
     469                complete(String(reinterpret_cast<const UChar*>(fileData.data() + start), length / sizeof(UChar)));
     470            }
     471            return;
     472        }
     473
     474        // Older versions cannot recover the original JSON source from disk.
     475        complete({ });
     476    });
     477}
     478
    405479const std::error_category& contentExtensionStoreErrorCategory()
    406480{
  • trunk/Source/WebKit2/UIProcess/API/APIContentExtensionStore.h

    r213696 r213988  
    4343public:
    4444    enum class Error {
    45         LookupFailed = 6, // Mirrors value of WKErrorContentExtensionStoreLookupFailed
     45        LookupFailed = 1,
    4646        VersionMismatch,
    4747        CompileFailed,
     
    5151    // This should be incremented every time a functional change is made to the bytecode, file format, etc.
    5252    // to prevent crashing while loading old data.
    53     const static uint32_t CurrentContentExtensionFileVersion = 8;
     53    // Also update ContentExtensionStore::getContentExtensionSource to be able to find the original JSON
     54    // source from old versions.
     55    const static uint32_t CurrentContentExtensionFileVersion = 9;
    5456
    5557    static ContentExtensionStore& defaultStore();
     
    6769    void synchronousRemoveAllContentExtensions();
    6870    void invalidateContentExtensionVersion(const WTF::String& identifier);
     71    void getContentExtensionSource(const WTF::String& identifier, Function<void(WTF::String)>);
    6972
    7073private:
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/WKContentExtensionStore.mm

    r213696 r213988  
    3030#if WK_API_ENABLED
    3131
     32#import "APIContentExtensionStore.h"
    3233#import "WKErrorInternal.h"
     34
     35static WKErrorCode toWKErrorCode(const std::error_code& error)
     36{
     37    ASSERT(error.category() == API::contentExtensionStoreErrorCategory());
     38    switch (static_cast<API::ContentExtensionStore::Error>(error.value())) {
     39    case API::ContentExtensionStore::Error::LookupFailed:
     40        return WKErrorContentExtensionStoreLookupFailed;
     41    case API::ContentExtensionStore::Error::VersionMismatch:
     42        return WKErrorContentExtensionStoreVersionMismatch;
     43    case API::ContentExtensionStore::Error::CompileFailed:
     44        return WKErrorContentExtensionStoreCompileFailed;
     45    case API::ContentExtensionStore::Error::RemoveFailed:
     46        return WKErrorContentExtensionStoreRemoveFailed;
     47    }
     48    ASSERT_NOT_REACHED();
     49    return WKErrorUnknown;
     50}
    3351
    3452@implementation WKContentExtensionStore
     
    93111
    94112            auto userInfo = @{NSHelpAnchorErrorKey: [NSString stringWithFormat:@"Extension lookup failed: %s", error.message().c_str()]};
    95             ASSERT(error.value() == WKErrorContentExtensionStoreLookupFailed || error.value() == WKErrorContentExtensionStoreVersionMismatch);
    96             rawHandler(nil, [NSError errorWithDomain:WKErrorDomain code:error.value() userInfo:userInfo]);
     113            auto wkError = toWKErrorCode(error);
     114            ASSERT(wkError == WKErrorContentExtensionStoreLookupFailed || wkError == WKErrorContentExtensionStoreVersionMismatch);
     115            rawHandler(nil, [NSError errorWithDomain:WKErrorDomain code:wkError userInfo:userInfo]);
    97116            return;
    98117        }
     
    112131
    113132            auto userInfo = @{NSHelpAnchorErrorKey: [NSString stringWithFormat:@"Extension removal failed: %s", error.message().c_str()]};
    114             ASSERT(error.value() == WKErrorContentExtensionStoreRemoveFailed);
     133            ASSERT(toWKErrorCode(error) == WKErrorContentExtensionStoreRemoveFailed);
    115134            rawHandler([NSError errorWithDomain:WKErrorDomain code:WKErrorContentExtensionStoreRemoveFailed userInfo:userInfo]);
    116135            return;
     
    145164}
    146165
     166- (void)_getContentExtensionSourceForIdentifier:(NSString *)identifier completionHandler:(void (^)(NSString*))completionHandler
     167{
     168    auto handler = adoptNS([completionHandler copy]);
     169    _contentExtensionStore->getContentExtensionSource(identifier, [handler](String source) {
     170        auto rawHandler = (void (^)(NSString *))handler.get();
     171        if (source.isNull())
     172            rawHandler(nil);
     173        else
     174            rawHandler(source);
     175    });
     176}
     177
    147178// NS_RELEASES_ARGUMENT to keep peak memory usage low.
    148179
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/WKContentExtensionStorePrivate.h

    r213696 r213988  
    3333- (void)_removeAllContentExtensions;
    3434- (void)_invalidateContentExtensionVersionForIdentifier:(NSString *)identifier;
     35- (void)_getContentExtensionSourceForIdentifier:(NSString *)identifier completionHandler:(void (^)(NSString*))completionHandler;
    3536
    3637// NS_RELEASES_ARGUMENT to keep peak memory usage low.
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/WKError.h

    r213696 r213988  
    4343 @constant WKErrorJavaScriptResultTypeIsUnsupported    Indicates that the result of JavaScript execution could not be returned.
    4444 @constant WKErrorContentExtensionStoreLookupFailed    Indicates that looking up a WKUserContentExtension failed.
    45  @constant WKErrorContentExtensionStoreVersionMismatch Indicates that looking up a WKUserContentExtension found an extension with an incompatible binary version.
     45 @constant WKErrorContentExtensionStoreVersionMismatch Indicates that the WKUserContentExtension version did not match the latest.
    4646 @constant WKErrorContentExtensionStoreCompileFailed   Indicates that compiling a WKUserContentExtension failed.
    4747 @constant WKErrorContentExtensionStoreRemoveFailed    Indicates that removing a WKUserContentExtension failed.
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/_WKUserContentExtensionStore.h

    r213696 r213988  
    4545
    4646typedef NS_ENUM(NSInteger, _WKUserContentExtensionStoreErrorCode) {
    47     _WKUserContentExtensionStoreErrorLookupFailed = 6, // Mirrors value of WKErrorContentExtensionStoreLookupFailed
     47    _WKUserContentExtensionStoreErrorLookupFailed,
    4848    _WKUserContentExtensionStoreErrorVersionMismatch,
    4949    _WKUserContentExtensionStoreErrorCompileFailed,
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/_WKUserContentExtensionStore.mm

    r213696 r213988  
    3939NSString * const _WKUserContentExtensionsDomain = @"WKErrorDomain";
    4040
     41static NSError *toUserContentExtensionStoreError(const NSError *error)
     42{
     43    if (!error)
     44        return nil;
     45
     46    ASSERT(error.domain == WKErrorDomain);
     47    switch (error.code) {
     48    case WKErrorContentExtensionStoreLookupFailed:
     49        return [NSError errorWithDomain:_WKUserContentExtensionsDomain code:_WKUserContentExtensionStoreErrorLookupFailed userInfo:error.userInfo];
     50    case WKErrorContentExtensionStoreVersionMismatch:
     51        return [NSError errorWithDomain:_WKUserContentExtensionsDomain code:_WKUserContentExtensionStoreErrorVersionMismatch userInfo:error.userInfo];
     52    case WKErrorContentExtensionStoreCompileFailed:
     53        return [NSError errorWithDomain:_WKUserContentExtensionsDomain code:_WKUserContentExtensionStoreErrorCompileFailed userInfo:error.userInfo];
     54    case WKErrorContentExtensionStoreRemoveFailed:
     55        return [NSError errorWithDomain:_WKUserContentExtensionsDomain code:_WKUserContentExtensionStoreErrorRemoveFailed userInfo:error.userInfo];
     56    default:
     57        RELEASE_ASSERT_NOT_REACHED();
     58    }
     59}
     60
    4161@implementation _WKUserContentExtensionStore
    4262
     
    5575    [_contentExtensionStore _compileContentExtensionForIdentifier:identifier encodedContentExtension:encodedContentExtension completionHandler:^(WKContentExtension *contentExtension, NSError *error) {
    5676        _WKUserContentFilter *contentFilter = contentExtension ? [[[_WKUserContentFilter alloc] _initWithWKContentExtension:contentExtension] autorelease] : nil;
    57         completionHandler(contentFilter, error);
     77        completionHandler(contentFilter, toUserContentExtensionStoreError(error));
    5878    }];
    5979}
     
    6383    [_contentExtensionStore lookupContentExtensionForIdentifier:identifier completionHandler:^(WKContentExtension *contentExtension, NSError *error) {
    6484        _WKUserContentFilter *contentFilter = contentExtension ? [[[_WKUserContentFilter alloc] _initWithWKContentExtension:contentExtension] autorelease] : nil;
    65         completionHandler(contentFilter, error);
     85        completionHandler(contentFilter, toUserContentExtensionStoreError(error));
    6686    }];
    6787}
     
    6989- (void)removeContentExtensionForIdentifier:(NSString *)identifier completionHandler:(void (^)(NSError *))completionHandler
    7090{
    71     [_contentExtensionStore removeContentExtensionForIdentifier:identifier completionHandler:completionHandler];
     91    [_contentExtensionStore removeContentExtensionForIdentifier:identifier completionHandler:^(NSError *error) {
     92        completionHandler(toUserContentExtensionStoreError(error));
     93    }];
    7294}
    7395
  • trunk/Tools/ChangeLog

    r213986 r213988  
     12017-03-15  Alex Christensen  <achristensen@webkit.org>
     2
     3        Compiled content extensions should include the JSON source
     4        https://bugs.webkit.org/show_bug.cgi?id=169643
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
     9        * TestWebKitAPI/Tests/WebKit2Cocoa/WKUserContentExtensionStore.mm:
     10        (TEST_F):
     11
    1122017-03-15  Kocsen Chung  <kocsen_chung@apple.com>
    213
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp

    r213669 r213988  
    100100        EXPECT_EQ(data.topURLFilters.size(), 0ull);
    101101    }
     102
     103    void writeSource(const String&) final { }
    102104
    103105    void writeActions(Vector<ContentExtensions::SerializedActionByte>&& actions, bool conditionsApplyOnlyToDomain) final
  • trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKUserContentExtensionStore.mm

    r213696 r213988  
    147147    }];
    148148    TestWebKitAPI::Util::run(&doneLookingUp);
     149
     150    __block bool doneGettingSource = false;
     151    [[WKContentExtensionStore defaultStore] _getContentExtensionSourceForIdentifier:@"TestExtension" completionHandler:^(NSString* source) {
     152        EXPECT_NULL(source);
     153        doneGettingSource = true;
     154    }];
     155    TestWebKitAPI::Util::run(&doneGettingSource);
    149156}
    150157
     
    184191}
    185192
     193TEST_F(WKContentExtensionStoreTest, NonDefaultStore)
     194{
     195    NSURL *tempDir = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"ContentExtensionTest"] isDirectory:YES];
     196    WKContentExtensionStore *store = [WKContentExtensionStore storeWithURL:tempDir];
     197    NSString *identifier = @"TestExtension";
     198    NSString *fileName = @"ContentExtension-TestExtension";
     199
     200    __block bool doneCompiling = false;
     201    [store compileContentExtensionForIdentifier:identifier encodedContentExtension:basicFilter completionHandler:^(WKContentExtension *filter, NSError *error) {
     202        EXPECT_NOT_NULL(filter);
     203        EXPECT_NULL(error);
     204        doneCompiling = true;
     205    }];
     206    TestWebKitAPI::Util::run(&doneCompiling);
     207
     208    NSData *data = [NSData dataWithContentsOfURL:[tempDir URLByAppendingPathComponent:fileName]];
     209    EXPECT_NOT_NULL(data);
     210    EXPECT_EQ(data.length, 228u);
     211   
     212    __block bool doneCheckingSource = false;
     213    [store _getContentExtensionSourceForIdentifier:identifier completionHandler:^(NSString *source) {
     214        EXPECT_NOT_NULL(source);
     215        EXPECT_STREQ(basicFilter.UTF8String, source.UTF8String);
     216        doneCheckingSource = true;
     217    }];
     218    TestWebKitAPI::Util::run(&doneCheckingSource);
     219   
     220    __block bool doneRemoving = false;
     221    [store removeContentExtensionForIdentifier:identifier completionHandler:^(NSError *error) {
     222        EXPECT_NULL(error);
     223        doneRemoving = true;
     224    }];
     225    TestWebKitAPI::Util::run(&doneRemoving);
     226
     227    NSData *dataAfterRemoving = [NSData dataWithContentsOfURL:[tempDir URLByAppendingPathComponent:fileName]];
     228    EXPECT_NULL(dataAfterRemoving);
     229}
     230
     231TEST_F(WKContentExtensionStoreTest, NonASCIISource)
     232{
     233    static NSString *nonASCIIFilter = @"[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*webkit.org\"}, \"unused\":\"💩\"}]";
     234    NSURL *tempDir = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"ContentExtensionTest"] isDirectory:YES];
     235    WKContentExtensionStore *store = [WKContentExtensionStore storeWithURL:tempDir];
     236    NSString *identifier = @"TestExtension";
     237    NSString *fileName = @"ContentExtension-TestExtension";
     238   
     239    __block bool done = false;
     240    [store compileContentExtensionForIdentifier:identifier encodedContentExtension:nonASCIIFilter completionHandler:^(WKContentExtension *filter, NSError *error) {
     241        EXPECT_NOT_NULL(filter);
     242        EXPECT_NULL(error);
     243
     244        [store _getContentExtensionSourceForIdentifier:identifier completionHandler:^(NSString *source) {
     245            EXPECT_NOT_NULL(source);
     246            EXPECT_STREQ(nonASCIIFilter.UTF8String, source.UTF8String);
     247
     248            [store _removeAllContentExtensions];
     249            NSData *dataAfterRemoving = [NSData dataWithContentsOfURL:[tempDir URLByAppendingPathComponent:fileName]];
     250            EXPECT_NULL(dataAfterRemoving);
     251
     252            done = true;
     253        }];
     254    }];
     255    TestWebKitAPI::Util::run(&done);
     256}
     257
    186258#endif
Note: See TracChangeset for help on using the changeset viewer.