Changeset 222602 in webkit


Ignore:
Timestamp:
Sep 27, 2017 10:43:39 PM (7 years ago)
Author:
achristensen@apple.com
Message:

Add WKContentRuleList notify action type
https://bugs.webkit.org/show_bug.cgi?id=177013
<rdar://problem/31073936>

Reviewed by Darin Adler.

Source/WebCore:

Covered by new API tests.

  • contentextensions/ContentExtensionActions.h:

(WebCore::ContentExtensions::hasStringArgument):

  • contentextensions/ContentExtensionCompiler.cpp:

(WebCore::ContentExtensions::resolvePendingDisplayNoneActions):
(WebCore::ContentExtensions::serializeActions):

  • contentextensions/ContentExtensionError.cpp:

(WebCore::ContentExtensions::contentExtensionErrorCategory):

  • contentextensions/ContentExtensionError.h:
  • contentextensions/ContentExtensionParser.cpp:

(WebCore::ContentExtensions::loadAction):

  • contentextensions/ContentExtensionRule.cpp:

(WebCore::ContentExtensions::Action::deserialize):
(WebCore::ContentExtensions::Action::deserializeType):
(WebCore::ContentExtensions::Action::serializedLength):

  • contentextensions/ContentExtensionRule.h:

(WebCore::ContentExtensions::Action::Action):

  • contentextensions/ContentExtensionsBackend.cpp:

(WebCore::ContentExtensions::ContentExtensionsBackend::processContentExtensionRulesForLoad):
(WebCore::ContentExtensions::ContentExtensionsBackend::processContentExtensionRulesForPingLoad):
(WebCore::ContentExtensions::applyBlockedStatusToRequest):

  • loader/FrameLoader.cpp:

(WebCore::FrameLoader::loadResourceSynchronously):

  • loader/PingLoader.cpp:

(WebCore::processContentExtensionRulesForLoad):

  • loader/ResourceLoader.cpp:

(WebCore::ResourceLoader::willSendRequestInternal):

  • loader/cache/CachedResourceLoader.cpp:

(WebCore::CachedResourceLoader::requestResource):

  • loader/cache/CachedResourceRequest.cpp:

(WebCore::CachedResourceRequest::applyBlockedStatus):

  • loader/cache/CachedResourceRequest.h:
  • page/ChromeClient.h:

Source/WebKit:

  • NetworkProcess/PingLoad.cpp:

(WebKit::PingLoad::processContentExtensionRulesForLoad):

  • UIProcess/API/APINavigationClient.h:

(API::NavigationClient::contentRuleListNotification):

  • UIProcess/API/C/WKPage.cpp:

(WKPageSetPageNavigationClient):

  • UIProcess/API/C/WKPageNavigationClient.h:
  • UIProcess/API/Cocoa/WKNavigationDelegatePrivate.h:
  • UIProcess/Cocoa/NavigationState.h:
  • UIProcess/Cocoa/NavigationState.mm:

(WebKit::NavigationState::setNavigationDelegate):
(WebKit::NavigationState::NavigationClient::contentRuleListNotification):

  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::contentRuleListNotification):

  • UIProcess/WebPageProxy.h:
  • UIProcess/WebPageProxy.messages.in:
  • WebProcess/WebCoreSupport/WebChromeClient.cpp:

(WebKit::WebChromeClient::contentRuleListNotification):

  • WebProcess/WebCoreSupport/WebChromeClient.h:

Tools:

  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:

(WebCore::ContentExtensions::operator<<):
(TestWebKitAPI::InMemoryCompiledContentExtension::create):
(TestWebKitAPI::InMemoryCompiledContentExtension::data):
(TestWebKitAPI::InMemoryCompiledContentExtension::InMemoryCompiledContentExtension):
(TestWebKitAPI::makeBackend):
(TestWebKitAPI::TEST_F):
(TestWebKitAPI::actionsEqual):
(TestWebKitAPI::sequenceInstances):
(TestWebKitAPI::InMemoryCompiledContentExtension::createFromFilter): Deleted.
(TestWebKitAPI::InMemoryCompiledContentExtension::~InMemoryCompiledContentExtension): Deleted.

  • TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm: Added.

(-[ContentRuleListNotificationDelegate _webView:URL:contentRuleListIdentifiers:notifications:]):
(-[ContentRuleListNotificationDelegate webView:startURLSchemeTask:]):
(-[ContentRuleListNotificationDelegate webView:stopURLSchemeTask:]):
(-[ContentRuleListNotificationDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
(makeWarnContentRuleList):
(TEST):

Location:
trunk
Files:
1 added
32 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r222597 r222602  
     12017-09-27  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add WKContentRuleList notify action type
     4        https://bugs.webkit.org/show_bug.cgi?id=177013
     5        <rdar://problem/31073936>
     6
     7        Reviewed by Darin Adler.
     8
     9        Covered by new API tests.
     10
     11        * contentextensions/ContentExtensionActions.h:
     12        (WebCore::ContentExtensions::hasStringArgument):
     13        * contentextensions/ContentExtensionCompiler.cpp:
     14        (WebCore::ContentExtensions::resolvePendingDisplayNoneActions):
     15        (WebCore::ContentExtensions::serializeActions):
     16        * contentextensions/ContentExtensionError.cpp:
     17        (WebCore::ContentExtensions::contentExtensionErrorCategory):
     18        * contentextensions/ContentExtensionError.h:
     19        * contentextensions/ContentExtensionParser.cpp:
     20        (WebCore::ContentExtensions::loadAction):
     21        * contentextensions/ContentExtensionRule.cpp:
     22        (WebCore::ContentExtensions::Action::deserialize):
     23        (WebCore::ContentExtensions::Action::deserializeType):
     24        (WebCore::ContentExtensions::Action::serializedLength):
     25        * contentextensions/ContentExtensionRule.h:
     26        (WebCore::ContentExtensions::Action::Action):
     27        * contentextensions/ContentExtensionsBackend.cpp:
     28        (WebCore::ContentExtensions::ContentExtensionsBackend::processContentExtensionRulesForLoad):
     29        (WebCore::ContentExtensions::ContentExtensionsBackend::processContentExtensionRulesForPingLoad):
     30        (WebCore::ContentExtensions::applyBlockedStatusToRequest):
     31        * loader/FrameLoader.cpp:
     32        (WebCore::FrameLoader::loadResourceSynchronously):
     33        * loader/PingLoader.cpp:
     34        (WebCore::processContentExtensionRulesForLoad):
     35        * loader/ResourceLoader.cpp:
     36        (WebCore::ResourceLoader::willSendRequestInternal):
     37        * loader/cache/CachedResourceLoader.cpp:
     38        (WebCore::CachedResourceLoader::requestResource):
     39        * loader/cache/CachedResourceRequest.cpp:
     40        (WebCore::CachedResourceRequest::applyBlockedStatus):
     41        * loader/cache/CachedResourceRequest.h:
     42        * page/ChromeClient.h:
     43
    1442017-09-27  Wenson Hsieh  <wenson_hsieh@apple.com>
    245
  • trunk/Source/WebCore/contentextensions/ContentExtensionActions.h

    r222462 r222602  
    2828#if ENABLE(CONTENT_EXTENSIONS)
    2929
     30#include <wtf/HashSet.h>
     31#include <wtf/text/WTFString.h>
     32
    3033namespace WebCore {
    3134
     35class Page;
    3236class ResourceRequest;
    3337
     
    4044    BlockCookies,
    4145    CSSDisplayNoneSelector,
    42     IgnorePreviousRules = 3,
    43     MakeHTTPS = 4,
     46    Notify,
     47    IgnorePreviousRules,
     48    MakeHTTPS,
    4449};
     50
     51static inline bool hasStringArgument(ActionType actionType)
     52{
     53    switch (actionType) {
     54    case ActionType::CSSDisplayNoneSelector:
     55    case ActionType::Notify:
     56        return true;
     57    case ActionType::BlockLoad:
     58    case ActionType::BlockCookies:
     59    case ActionType::IgnorePreviousRules:
     60    case ActionType::MakeHTTPS:
     61        return false;
     62    }
     63    ASSERT_NOT_REACHED();
     64    return false;
     65}
    4566
    4667struct BlockedStatus {
     
    4869    bool blockedCookies { false };
    4970    bool madeHTTPS { false };
     71    HashSet<std::pair<String, String>> notifications;
    5072};
    5173
    52 WEBCORE_EXPORT void applyBlockedStatusToRequest(const BlockedStatus&, ResourceRequest&);
     74WEBCORE_EXPORT void applyBlockedStatusToRequest(const BlockedStatus&, Page*, ResourceRequest&);
    5375
    5476} // namespace ContentExtensions
  • trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp

    r222462 r222602  
    6969}
    7070
     71// css-display-none combining is special because we combine the string arguments with commas because we know they are css selectors.
    7172struct PendingDisplayNoneActions {
    72     Vector<String> selectors;
    73     Vector<unsigned> clientLocations;
     73    StringBuilder combinedSelectors;
     74    Vector<uint32_t> clientLocations;
    7475};
     76
    7577using PendingDisplayNoneActionsMap = HashMap<Trigger, PendingDisplayNoneActions, TriggerHash, TriggerHashTraits>;
    7678
    77 static void resolvePendingDisplayNoneActions(Vector<SerializedActionByte>& actions, Vector<unsigned>& actionLocations, PendingDisplayNoneActionsMap& pendingDisplayNoneActionsMap)
    78 {
    79     for (auto& slot : pendingDisplayNoneActionsMap) {
    80         PendingDisplayNoneActions& pendingActions = slot.value;
    81 
    82         StringBuilder combinedSelectors;
    83         for (unsigned i = 0; i < pendingActions.selectors.size(); ++i) {
    84             if (i)
    85                 combinedSelectors.append(',');
    86             combinedSelectors.append(pendingActions.selectors[i]);
    87         }
    88 
    89         unsigned actionLocation = actions.size();
     79static void resolvePendingDisplayNoneActions(Vector<SerializedActionByte>& actions, Vector<uint32_t>& actionLocations, PendingDisplayNoneActionsMap& map)
     80{
     81    for (auto& pendingDisplayNoneActions : map.values()) {
     82        uint32_t actionLocation = actions.size();
    9083        actions.append(static_cast<SerializedActionByte>(ActionType::CSSDisplayNoneSelector));
    91         serializeString(actions, combinedSelectors.toString());
    92         for (unsigned clientLocation : pendingActions.clientLocations)
     84        serializeString(actions, pendingDisplayNoneActions.combinedSelectors.toString());
     85        for (uint32_t clientLocation : pendingDisplayNoneActions.clientLocations)
    9386            actionLocations[clientLocation] = actionLocation;
    9487    }
    95     pendingDisplayNoneActionsMap.clear();
     88    map.clear();
    9689}
    9790
     
    10093    ASSERT(!actions.size());
    10194
    102     Vector<unsigned> actionLocations;
    103 
    104     // Order only matters because of IgnorePreviousRules. All other identical actions can be combined between each IgnorePreviousRules
    105     // and CSSDisplayNone strings can be combined if their triggers are identical.
     95    Vector<uint32_t> actionLocations;
     96
    10697    using ActionLocation = uint32_t;
    10798    using ActionMap = HashMap<ResourceFlags, ActionLocation, DefaultHash<ResourceFlags>::Hash, WTF::UnsignedWithZeroKeyHashTraits<ResourceFlags>>;
     99    using StringActionMap = HashMap<std::pair<String, ResourceFlags>, ActionLocation, DefaultHash<std::pair<String, ResourceFlags>>::Hash, PairHashTraits<HashTraits<String>, WTF::UnsignedWithZeroKeyHashTraits<ResourceFlags>>>;
    108100    ActionMap blockLoadActionsMap;
    109101    ActionMap blockCookiesActionsMap;
     
    111103    ActionMap ignorePreviousRuleActionsMap;
    112104    ActionMap makeHTTPSActionsMap;
     105    StringActionMap notifyActionsMap;
    113106
    114107    for (unsigned ruleIndex = 0; ruleIndex < ruleList.size(); ++ruleIndex) {
     
    123116            cssDisplayNoneActionsMap.clear();
    124117            makeHTTPSActionsMap.clear();
     118            notifyActionsMap.clear();
    125119        } else
    126120            ignorePreviousRuleActionsMap.clear();
     
    132126
    133127            actions.append(static_cast<SerializedActionByte>(actionType));
    134             if (actionType == ActionType::CSSDisplayNoneSelector)
     128            if (hasStringArgument(actionType))
    135129                serializeString(actions, rule.action().stringArgument());
     130            else
     131                ASSERT(rule.action().stringArgument().isNull());
    136132            continue;
    137133        }
     
    140136        unsigned actionLocation = std::numeric_limits<unsigned>::max();
    141137       
    142         auto findOrMakeActionLocation = [&] (ActionMap& map)
    143         {
     138        auto findOrMakeActionLocation = [&] (ActionMap& map) {
    144139            const auto existingAction = map.find(flags);
    145140            if (existingAction == map.end()) {
     
    150145                actionLocation = existingAction->value;
    151146        };
     147       
     148        auto findOrMakeStringActionLocation = [&] (StringActionMap& map) {
     149            const String& argument = rule.action().stringArgument();
     150            auto existingAction = map.find(std::make_pair(argument, flags));
     151            if (existingAction == map.end()) {
     152                actionLocation = actions.size();
     153                actions.append(static_cast<SerializedActionByte>(actionType));
     154                serializeString(actions, argument);
     155                map.set(std::make_pair(argument, flags), actionLocation);
     156            } else
     157                actionLocation = existingAction->value;
     158        };
    152159
    153160        switch (actionType) {
    154161        case ActionType::CSSDisplayNoneSelector: {
    155162            const auto addResult = cssDisplayNoneActionsMap.add(rule.trigger(), PendingDisplayNoneActions());
    156             PendingDisplayNoneActions& pendingDisplayNoneActions = addResult.iterator->value;
    157             pendingDisplayNoneActions.selectors.append(rule.action().stringArgument());
    158             pendingDisplayNoneActions.clientLocations.append(actionLocations.size());
     163            auto& pendingStringActions = addResult.iterator->value;
     164            if (!pendingStringActions.combinedSelectors.isEmpty())
     165                pendingStringActions.combinedSelectors.append(',');
     166            pendingStringActions.combinedSelectors.append(rule.action().stringArgument());
     167            pendingStringActions.clientLocations.append(actionLocations.size());
    159168
    160169            actionLocation = std::numeric_limits<unsigned>::max();
     
    172181        case ActionType::MakeHTTPS:
    173182            findOrMakeActionLocation(makeHTTPSActionsMap);
     183            break;
     184        case ActionType::Notify:
     185            findOrMakeStringActionLocation(notifyActionsMap);
    174186            break;
    175187        }
  • trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp

    r222462 r222602  
    8888            case ContentExtensionError::JSONTopURLAndDomainConditions:
    8989                return "A list cannot have if-domain and unless-domain mixed with if-top-url and unless-top-url";
     90            case ContentExtensionError::JSONInvalidNotification:
     91                return "A notify action must have a string notification";
    9092            }
    9193
  • trunk/Source/WebCore/contentextensions/ContentExtensionError.h

    r222462 r222602  
    5959    JSONInvalidActionType,
    6060    JSONInvalidCSSDisplayNoneActionType,
     61    JSONInvalidNotification,
    6162    JSONInvalidRegex,
    6263};
  • trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp

    r222462 r222602  
    249249
    250250    const JSValue actionObject = ruleObject.get(&exec, Identifier::fromString(&exec, "action"));
    251     if (!actionObject || scope.exception() || !actionObject.isObject())
     251    if (scope.exception() || !actionObject.isObject())
    252252        return makeUnexpected(ContentExtensionError::JSONInvalidAction);
    253253
    254254    const JSValue typeObject = actionObject.get(&exec, Identifier::fromString(&exec, "type"));
    255     if (!typeObject || scope.exception() || !typeObject.isString())
     255    if (scope.exception() || !typeObject.isString())
    256256        return makeUnexpected(ContentExtensionError::JSONInvalidActionType);
    257257
     
    266266    if (actionType == "css-display-none") {
    267267        JSValue selector = actionObject.get(&exec, Identifier::fromString(&exec, "selector"));
    268         if (!selector || scope.exception() || !selector.isString())
     268        if (scope.exception() || !selector.isString())
    269269            return makeUnexpected(ContentExtensionError::JSONInvalidCSSDisplayNoneActionType);
    270270
     
    278278    if (actionType == "make-https")
    279279        return {{ ActionType::MakeHTTPS }};
     280    if (actionType == "notify") {
     281        JSValue notification = actionObject.get(&exec, Identifier::fromString(&exec, "notification"));
     282        if (scope.exception() || !notification.isString())
     283            return makeUnexpected(ContentExtensionError::JSONInvalidNotification);
     284        return { Action(ActionType::Notify, asString(notification)->value(&exec)) };
     285    }
    280286    return makeUnexpected(ContentExtensionError::JSONInvalidActionType);
    281287}
  • trunk/Source/WebCore/contentextensions/ContentExtensionRule.cpp

    r222462 r222602  
    6767        return Action(actionType, location);
    6868    case ActionType::CSSDisplayNoneSelector:
     69    case ActionType::Notify:
    6970        return Action(actionType, deserializeString(actions, actionsLength, location + sizeof(ActionType)), location);
    7071    }
     
    7980    case ActionType::BlockCookies:
    8081    case ActionType::BlockLoad:
     82    case ActionType::Notify:
    8183    case ActionType::IgnorePreviousRules:
    8284    case ActionType::CSSDisplayNoneSelector:
     
    9698    case ActionType::MakeHTTPS:
    9799        return sizeof(ActionType);
     100    case ActionType::Notify:
    98101    case ActionType::CSSDisplayNoneSelector: {
    99102        uint32_t prefixLength = sizeof(ActionType) + sizeof(uint32_t) + sizeof(bool);
  • trunk/Source/WebCore/contentextensions/ContentExtensionRule.h

    r222462 r222602  
    136136        , m_stringArgument(stringArgument)
    137137    {
    138         ASSERT(type == ActionType::CSSDisplayNoneSelector);
     138        ASSERT(hasStringArgument(type));
    139139    }
    140140
     
    143143        , m_actionID(actionID)
    144144    {
    145         ASSERT(type != ActionType::CSSDisplayNoneSelector);
     145        ASSERT(!hasStringArgument(type));
    146146    }
    147147
  • trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp

    r222462 r222602  
    2929#if ENABLE(CONTENT_EXTENSIONS)
    3030
     31#include "Chrome.h"
     32#include "ChromeClient.h"
    3133#include "CompiledContentExtension.h"
    3234#include "ContentExtension.h"
     
    3941#include "FrameLoaderClient.h"
    4042#include "MainFrame.h"
     43#include "Page.h"
    4144#include "ResourceLoadInfo.h"
    4245#include "URL.h"
     
    171174    bool willBlockCookies = false;
    172175    bool willMakeHTTPS = false;
     176    HashSet<std::pair<String, String>> notifications;
    173177    for (const auto& action : actions.first) {
    174178        switch (action.type()) {
     
    184188            else if (currentDocument)
    185189                currentDocument->extensionStyleSheets().addDisplayNoneSelector(action.extensionIdentifier(), action.stringArgument(), action.actionID());
     190            break;
     191        case ContentExtensions::ActionType::Notify:
     192            notifications.add(std::make_pair(action.extensionIdentifier(), action.stringArgument()));
    186193            break;
    187194        case ContentExtensions::ActionType::MakeHTTPS: {
     
    214221            currentDocument->addConsoleMessage(MessageSource::ContentBlocker, MessageLevel::Info, makeString("Content blocker prevented frame displaying ", mainDocumentURL.string(), " from loading a resource from ", url.string()));
    215222    }
    216     return { willBlockLoad, willBlockCookies, willMakeHTTPS };
     223    return { willBlockLoad, willBlockCookies, willMakeHTTPS, WTFMove(notifications) };
    217224}
    218225
     
    241248            break;
    242249        case ContentExtensions::ActionType::CSSDisplayNoneSelector:
     250        case ContentExtensions::ActionType::Notify:
    243251            break;
    244252        case ContentExtensions::ActionType::IgnorePreviousRules:
     
    247255    }
    248256
    249     return { willBlockLoad, willBlockCookies, willMakeHTTPS };
     257    return { willBlockLoad, willBlockCookies, willMakeHTTPS, { } };
    250258}
    251259
     
    256264}
    257265
    258 void applyBlockedStatusToRequest(const BlockedStatus& status, ResourceRequest& request)
    259 {
     266void applyBlockedStatusToRequest(const BlockedStatus& status, Page* page, ResourceRequest& request)
     267{
     268    if (page && !status.notifications.isEmpty())
     269        page->chrome().client().contentRuleListNotification(request.url(), status.notifications);
     270
    260271    if (status.blockedCookies)
    261272        request.setAllowCookies(false);
  • trunk/Source/WebCore/loader/FrameLoader.cpp

    r222472 r222602  
    27822782            if (m_documentLoader) {
    27832783                auto blockedStatus = page->userContentProvider().processContentExtensionRulesForLoad(newRequest.url(), ResourceType::Raw, *m_documentLoader);
    2784                 applyBlockedStatusToRequest(blockedStatus, newRequest);
     2784                applyBlockedStatusToRequest(blockedStatus, page, newRequest);
    27852785                if (blockedStatus.blockedLoad) {
    27862786                    newRequest = { };
  • trunk/Source/WebCore/loader/PingLoader.cpp

    r222462 r222602  
    7676        return false;
    7777    auto status = page->userContentProvider().processContentExtensionRulesForLoad(request.url(), resourceType, *documentLoader);
    78     applyBlockedStatusToRequest(status, request);
     78    applyBlockedStatusToRequest(status, page, request);
    7979    return status.blockedLoad;
    8080}
  • trunk/Source/WebCore/loader/ResourceLoader.cpp

    r222467 r222602  
    346346
    347347#if ENABLE(CONTENT_EXTENSIONS)
    348     if (frameLoader()) {
     348    if (!redirectResponse.isNull() && frameLoader()) {
    349349        Page* page = frameLoader()->frame().page();
    350350        if (page && m_documentLoader) {
    351351            auto blockedStatus = page->userContentProvider().processContentExtensionRulesForLoad(request.url(), m_resourceType, *m_documentLoader);
    352             applyBlockedStatusToRequest(blockedStatus, request);
     352            applyBlockedStatusToRequest(blockedStatus, page, request);
    353353            if (blockedStatus.blockedLoad) {
    354354                request = { };
  • trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp

    r222467 r222602  
    726726    if (frame() && frame()->mainFrame().page() && m_documentLoader) {
    727727        const auto& resourceRequest = request.resourceRequest();
    728         auto blockedStatus = frame()->mainFrame().page()->userContentProvider().processContentExtensionRulesForLoad(resourceRequest.url(), toResourceType(type), *m_documentLoader);
    729         request.applyBlockedStatus(blockedStatus);
     728        auto* page = frame()->mainFrame().page();
     729        auto blockedStatus = page->userContentProvider().processContentExtensionRulesForLoad(resourceRequest.url(), toResourceType(type), *m_documentLoader);
     730        request.applyBlockedStatus(blockedStatus, page);
    730731        if (blockedStatus.blockedLoad) {
    731732            RELEASE_LOG_IF_ALLOWED("requestResource: Resource blocked by content blocker (frame = %p)", frame());
  • trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp

    r222467 r222602  
    213213#if ENABLE(CONTENT_EXTENSIONS)
    214214
    215 void CachedResourceRequest::applyBlockedStatus(const ContentExtensions::BlockedStatus& blockedStatus)
    216 {
    217     ContentExtensions::applyBlockedStatusToRequest(blockedStatus, m_resourceRequest);
     215void CachedResourceRequest::applyBlockedStatus(const ContentExtensions::BlockedStatus& blockedStatus, Page* page)
     216{
     217    ContentExtensions::applyBlockedStatusToRequest(blockedStatus, page, m_resourceRequest);
    218218}
    219219
  • trunk/Source/WebCore/loader/cache/CachedResourceRequest.h

    r222462 r222602  
    7777    void removeFragmentIdentifierIfNeeded();
    7878#if ENABLE(CONTENT_EXTENSIONS)
    79     void applyBlockedStatus(const ContentExtensions::BlockedStatus&);
     79    void applyBlockedStatus(const ContentExtensions::BlockedStatus&, Page*);
    8080#endif
    8181    void setDomainForCachePartition(Document&);
  • trunk/Source/WebCore/page/ChromeClient.h

    r222462 r222602  
    371371    virtual void disableSuddenTermination() { }
    372372
     373    virtual void contentRuleListNotification(const WebCore::URL&, const HashSet<std::pair<String, String>>&) { };
     374
    373375#if PLATFORM(WIN)
    374376    virtual void setLastSetCursorToCurrentCursor() = 0;
  • trunk/Source/WebKit/ChangeLog

    r222595 r222602  
     12017-09-27  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add WKContentRuleList notify action type
     4        https://bugs.webkit.org/show_bug.cgi?id=177013
     5        <rdar://problem/31073936>
     6
     7        Reviewed by Darin Adler.
     8
     9        * NetworkProcess/PingLoad.cpp:
     10        (WebKit::PingLoad::processContentExtensionRulesForLoad):
     11        * UIProcess/API/APINavigationClient.h:
     12        (API::NavigationClient::contentRuleListNotification):
     13        * UIProcess/API/C/WKPage.cpp:
     14        (WKPageSetPageNavigationClient):
     15        * UIProcess/API/C/WKPageNavigationClient.h:
     16        * UIProcess/API/Cocoa/WKNavigationDelegatePrivate.h:
     17        * UIProcess/Cocoa/NavigationState.h:
     18        * UIProcess/Cocoa/NavigationState.mm:
     19        (WebKit::NavigationState::setNavigationDelegate):
     20        (WebKit::NavigationState::NavigationClient::contentRuleListNotification):
     21        * UIProcess/WebPageProxy.cpp:
     22        (WebKit::WebPageProxy::contentRuleListNotification):
     23        * UIProcess/WebPageProxy.h:
     24        * UIProcess/WebPageProxy.messages.in:
     25        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
     26        (WebKit::WebChromeClient::contentRuleListNotification):
     27        * WebProcess/WebCoreSupport/WebChromeClient.h:
     28
    1292017-09-27  Wenson Hsieh  <wenson_hsieh@apple.com>
    230
  • trunk/Source/WebKit/NetworkProcess/PingLoad.cpp

    r222570 r222602  
    324324{
    325325    auto status = contentExtensionsBackend().processContentExtensionRulesForPingLoad(request.url(), m_parameters.mainDocumentURL);
    326     applyBlockedStatusToRequest(status, request);
     326    applyBlockedStatusToRequest(status, nullptr, request);
    327327    return status;
    328328}
  • trunk/Source/WebKit/UIProcess/API/APINavigationClient.h

    r222583 r222602  
    107107    }
    108108   
     109    virtual void contentRuleListNotification(WebKit::WebPageProxy&, WebCore::URL&&, Vector<WTF::String>&&, Vector<WTF::String>&&) { };
     110   
    109111#if ENABLE(NETSCAPE_PLUGIN_API)
    110112    virtual WebKit::PluginModuleLoadPolicy decidePolicyForPluginLoad(WebKit::WebPageProxy&, WebKit::PluginModuleLoadPolicy currentPluginLoadPolicy, Dictionary*, WTF::String&)
  • trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp

    r222583 r222602  
    103103
    104104template<> struct ClientTraits<WKPageNavigationClientBase> {
    105     typedef std::tuple<WKPageNavigationClientV0, WKPageNavigationClientV1> Versions;
     105    typedef std::tuple<WKPageNavigationClientV0, WKPageNavigationClientV1, WKPageNavigationClientV2> Versions;
    106106};
    107107
     
    22962296        }
    22972297       
     2298        void contentRuleListNotification(WebPageProxy& page, URL&& url, Vector<String>&& listIdentifiers, Vector<String>&& notifications) final
     2299        {
     2300            if (!m_client.contentRuleListNotification)
     2301                return;
     2302
     2303            Vector<RefPtr<API::Object>> apiListIdentifiers;
     2304            for (const auto& identifier : listIdentifiers)
     2305                apiListIdentifiers.append(API::String::create(identifier));
     2306
     2307            Vector<RefPtr<API::Object>> apiNotifications;
     2308            for (const auto& notification : notifications)
     2309                apiNotifications.append(API::String::create(notification));
     2310
     2311            m_client.contentRuleListNotification(toAPI(&page), toURLRef(url.string().impl()), toAPI(API::Array::create(WTFMove(apiListIdentifiers)).ptr()), toAPI(API::Array::create(WTFMove(apiNotifications)).ptr()), m_client.base.clientInfo);
     2312        }
    22982313#if ENABLE(NETSCAPE_PLUGIN_API)
    22992314        PluginModuleLoadPolicy decidePolicyForPluginLoad(WebPageProxy& page, PluginModuleLoadPolicy currentPluginLoadPolicy, API::Dictionary* pluginInformation, String& unavailabilityDescription) override
  • trunk/Source/WebKit/UIProcess/API/C/WKPageNavigationClient.h

    r222462 r222602  
    8181typedef void (*WKPageNavigationDidRemoveNavigationGestureSnapshot)(WKPageRef page, const void* clientInfo);
    8282
     83typedef void (*WKPageNavigationContentRuleListNotificationCallback)(WKPageRef, WKURLRef, WKArrayRef, WKArrayRef, const void* clientInfo);
    8384
    8485typedef struct WKPageNavigationClientBase {
     
    144145} WKPageNavigationClientV1;
    145146
     147typedef struct WKPageNavigationClientV2 {
     148    WKPageNavigationClientBase base;
     149   
     150    // Version 0.
     151    WKPageNavigationDecidePolicyForNavigationActionCallback decidePolicyForNavigationAction;
     152    WKPageNavigationDecidePolicyForNavigationResponseCallback decidePolicyForNavigationResponse;
     153    WKPageNavigationDecidePolicyForPluginLoadCallback decidePolicyForPluginLoad;
     154    WKPageNavigationDidStartProvisionalNavigationCallback didStartProvisionalNavigation;
     155    WKPageNavigationDidReceiveServerRedirectForProvisionalNavigationCallback didReceiveServerRedirectForProvisionalNavigation;
     156    WKPageNavigationDidFailProvisionalNavigationCallback didFailProvisionalNavigation;
     157    WKPageNavigationDidCommitNavigationCallback didCommitNavigation;
     158    WKPageNavigationDidFinishNavigationCallback didFinishNavigation;
     159    WKPageNavigationDidFailNavigationCallback didFailNavigation;
     160    WKPageNavigationDidFailProvisionalLoadInSubframeCallback didFailProvisionalLoadInSubframe;
     161    WKPageNavigationDidFinishDocumentLoadCallback didFinishDocumentLoad;
     162    WKPageNavigationDidSameDocumentNavigationCallback didSameDocumentNavigation;
     163    WKPageNavigationRenderingProgressDidChangeCallback renderingProgressDidChange;
     164    WKPageNavigationCanAuthenticateAgainstProtectionSpaceCallback canAuthenticateAgainstProtectionSpace;
     165    WKPageNavigationDidReceiveAuthenticationChallengeCallback didReceiveAuthenticationChallenge;
     166    WKPageNavigationWebProcessDidCrashCallback webProcessDidCrash;
     167    WKPageNavigationCopyWebCryptoMasterKeyCallback copyWebCryptoMasterKey;
     168    WKPageNavigationDidBeginNavigationGesture didBeginNavigationGesture;
     169    WKPageNavigationWillEndNavigationGesture willEndNavigationGesture;
     170    WKPageNavigationDidEndNavigationGesture didEndNavigationGesture;
     171    WKPageNavigationDidRemoveNavigationGestureSnapshot didRemoveNavigationGestureSnapshot;
     172   
     173    // Version 1.
     174    WKPageNavigationWebProcessDidTerminateCallback webProcessDidTerminate;
     175
     176    // Version 2.
     177    WKPageNavigationContentRuleListNotificationCallback contentRuleListNotification;
     178} WKPageNavigationClientV2;
     179
    146180#ifdef __cplusplus
    147181}
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKNavigationDelegatePrivate.h

    r222462 r222602  
    7979- (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler WK_API_AVAILABLE(macosx(10.12.3), ios(10.3));
    8080
     81- (void)_webView:(WKWebView *)webView URL:(NSURL *)url contentRuleListIdentifiers:(NSArray<NSString *> *)identifiers notifications:(NSArray<NSString *> *)notifications WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
     82
    8183#if TARGET_OS_IPHONE
    8284- (void)_webView:(WKWebView *)webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:(NSString *)fileName uti:(NSString *)uti;
  • trunk/Source/WebKit/UIProcess/Cocoa/NavigationState.h

    r222583 r222602  
    122122#endif
    123123
     124        void contentRuleListNotification(WebPageProxy&, WebCore::URL&&, Vector<String>&&, Vector<String>&&) final;
    124125        void decidePolicyForNavigationAction(WebPageProxy&, Ref<API::NavigationAction>&&, Ref<WebFramePolicyListenerProxy>&&, API::Object* userData) override;
    125126        void decidePolicyForNavigationResponse(WebPageProxy&, API::NavigationResponse&, Ref<WebFramePolicyListenerProxy>&&, API::Object* userData) override;
     
    202203        bool webViewWillSnapshotBackForwardListItem : 1;
    203204        bool webViewNavigationGestureSnapshotWasRemoved : 1;
     205        bool webViewURLContentRuleListIdentifiersNotifications : 1;
    204206#if USE(QUICK_LOOK)
    205207        bool webViewDidStartLoadForQuickLookDocumentInMainFrame : 1;
  • trunk/Source/WebKit/UIProcess/Cocoa/NavigationState.mm

    r222583 r222602  
    169169    m_navigationDelegateMethods.webViewWillSnapshotBackForwardListItem = [delegate respondsToSelector:@selector(_webView:willSnapshotBackForwardListItem:)];
    170170    m_navigationDelegateMethods.webViewNavigationGestureSnapshotWasRemoved = [delegate respondsToSelector:@selector(_webViewDidRemoveNavigationGestureSnapshot:)];
     171    m_navigationDelegateMethods.webViewURLContentRuleListIdentifiersNotifications = [delegate respondsToSelector:@selector(_webView:URL:contentRuleListIdentifiers:notifications:)];
    171172#if USE(QUICK_LOOK)
    172173    m_navigationDelegateMethods.webViewDidStartLoadForQuickLookDocumentInMainFrame = [delegate respondsToSelector:@selector(_webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:)];
     
    459460}
    460461
     462void NavigationState::NavigationClient::contentRuleListNotification(WebPageProxy&, WebCore::URL&& url, Vector<String>&& listIdentifiers, Vector<String>&& notifications)
     463{
     464    if (!m_navigationState.m_navigationDelegateMethods.webViewURLContentRuleListIdentifiersNotifications)
     465        return;
     466
     467    auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
     468    if (!navigationDelegate)
     469        return;
     470
     471    ASSERT(listIdentifiers.size() == notifications.size());
     472
     473    auto identifiers = adoptNS([[NSMutableArray alloc] initWithCapacity:listIdentifiers.size()]);
     474    for (auto& identifier : listIdentifiers)
     475        [identifiers addObject:identifier];
     476
     477    auto nsNotifications = adoptNS([[NSMutableArray alloc] initWithCapacity:notifications.size()]);
     478    for (auto& notification : notifications)
     479        [nsNotifications addObject:notification];
     480   
     481    [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView URL:url contentRuleListIdentifiers:identifiers.get() notifications:nsNotifications.get()];
     482}
     483   
    461484void NavigationState::NavigationClient::decidePolicyForNavigationResponse(WebPageProxy&, API::NavigationResponse& navigationResponse, Ref<WebFramePolicyListenerProxy>&& listener, API::Object* userData)
    462485{
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r222583 r222602  
    38003800}
    38013801
     3802void WebPageProxy::contentRuleListNotification(WebCore::URL&& url, Vector<String>&& identifiers, Vector<String>&& notifications)
     3803{
     3804    if (m_navigationClient)
     3805        m_navigationClient->contentRuleListNotification(*this, WTFMove(url), WTFMove(identifiers), WTFMove(notifications));
     3806}
     3807   
    38023808void WebPageProxy::didNavigateWithNavigationData(const WebNavigationDataStore& store, uint64_t frameID)
    38033809{
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r222583 r222602  
    12911291
    12921292    void willSubmitForm(uint64_t frameID, uint64_t sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, uint64_t listenerID, const UserData&);
     1293       
     1294    void contentRuleListNotification(WebCore::URL&&, Vector<String>&& identifiers, Vector<String>&& notifications);
    12931295
    12941296    // History client
  • trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in

    r222492 r222602  
    459459
    460460    HandleAutoFillButtonClick(WebKit::UserData userData);
     461    ContentRuleListNotification(WebCore::URL url, Vector<String> identifiers, Vector<String> notifications)
    461462
    462463#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp

    r222462 r222602  
    875875}
    876876
     877void WebChromeClient::contentRuleListNotification(const URL& url, const HashSet<std::pair<String, String>>& notificationPairs)
     878{
     879    Vector<String> identifiers;
     880    Vector<String> notifications;
     881    identifiers.reserveInitialCapacity(notificationPairs.size());
     882    notifications.reserveInitialCapacity(notificationPairs.size());
     883    for (auto& notification : notificationPairs) {
     884        identifiers.uncheckedAppend(notification.first);
     885        notifications.uncheckedAppend(notification.second);
     886    }
     887
     888    m_page.send(Messages::WebPageProxy::ContentRuleListNotification(url, identifiers, notifications));
     889}
     890
    877891bool WebChromeClient::adjustLayerFlushThrottling(LayerFlushThrottleState::Flags flags)
    878892{
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h

    r222462 r222602  
    209209    bool adjustLayerFlushThrottling(WebCore::LayerFlushThrottleState::Flags) final;
    210210
     211    void contentRuleListNotification(const WebCore::URL&, const HashSet<std::pair<String, String>>&) final;
     212   
    211213#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    212214    RefPtr<WebCore::DisplayRefreshMonitor> createDisplayRefreshMonitor(WebCore::PlatformDisplayID) const final;
  • trunk/Tools/ChangeLog

    r222595 r222602  
     12017-09-27  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add WKContentRuleList notify action type
     4        https://bugs.webkit.org/show_bug.cgi?id=177013
     5        <rdar://problem/31073936>
     6
     7        Reviewed by Darin Adler.
     8
     9        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     10        * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
     11        (WebCore::ContentExtensions::operator<<):
     12        (TestWebKitAPI::InMemoryCompiledContentExtension::create):
     13        (TestWebKitAPI::InMemoryCompiledContentExtension::data):
     14        (TestWebKitAPI::InMemoryCompiledContentExtension::InMemoryCompiledContentExtension):
     15        (TestWebKitAPI::makeBackend):
     16        (TestWebKitAPI::TEST_F):
     17        (TestWebKitAPI::actionsEqual):
     18        (TestWebKitAPI::sequenceInstances):
     19        (TestWebKitAPI::InMemoryCompiledContentExtension::createFromFilter): Deleted.
     20        (TestWebKitAPI::InMemoryCompiledContentExtension::~InMemoryCompiledContentExtension): Deleted.
     21        * TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm: Added.
     22        (-[ContentRuleListNotificationDelegate _webView:URL:contentRuleListIdentifiers:notifications:]):
     23        (-[ContentRuleListNotificationDelegate webView:startURLSchemeTask:]):
     24        (-[ContentRuleListNotificationDelegate webView:stopURLSchemeTask:]):
     25        (-[ContentRuleListNotificationDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
     26        (makeWarnContentRuleList):
     27        (TEST):
     28
    1292017-09-27  Wenson Hsieh  <wenson_hsieh@apple.com>
    230
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r222595 r222602  
    239239                5C9E59431D3EB5AC00E3C62E /* ApplicationCache.db-wal in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5C9E59401D3EB1DE00E3C62E /* ApplicationCache.db-wal */; };
    240240                5CA1DEC81F71F70100E71BD3 /* HTTPHeaderField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CA1DEC71F71F40700E71BD3 /* HTTPHeaderField.cpp */; };
     241                5CA1DED91F74A91A00E71BD3 /* ContentRuleListNotification.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5CA1DED81F74A87100E71BD3 /* ContentRuleListNotification.mm */; };
    241242                5CB18BA81F5645E300EE23C4 /* ClickAutoFillButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5CB18BA71F5645B200EE23C4 /* ClickAutoFillButton.mm */; };
    242243                5CB40B4E1F4B98D3007DC7B9 /* UIDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5CB40B4D1F4B98BE007DC7B9 /* UIDelegate.mm */; };
     
    13421343                5C9E59401D3EB1DE00E3C62E /* ApplicationCache.db-wal */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ApplicationCache.db-wal"; sourceTree = "<group>"; };
    13431344                5CA1DEC71F71F40700E71BD3 /* HTTPHeaderField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPHeaderField.cpp; sourceTree = "<group>"; };
     1345                5CA1DED81F74A87100E71BD3 /* ContentRuleListNotification.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentRuleListNotification.mm; sourceTree = "<group>"; };
    13441346                5CB18BA71F5645B200EE23C4 /* ClickAutoFillButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ClickAutoFillButton.mm; sourceTree = "<group>"; };
    13451347                5CB40B4D1F4B98BE007DC7B9 /* UIDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UIDelegate.mm; sourceTree = "<group>"; };
     
    19481950                                A14FC5861B8991B600D107EB /* ContentFiltering.mm */,
    19491951                                A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */,
     1952                                5CA1DED81F74A87100E71BD3 /* ContentRuleListNotification.mm */,
    19501953                                5C2936911D5BF63E00DEAB1E /* CookieAcceptPolicy.mm */,
    19511954                                9999108A1F393C8B008AD455 /* Copying.mm */,
     
    31713174                                A1146A8D1D2D7115000FE710 /* ContentFiltering.mm in Sources */,
    31723175                                A14FC5881B8991BF00D107EB /* ContentFiltering.mm in Sources */,
     3176                                5CA1DED91F74A91A00E71BD3 /* ContentRuleListNotification.mm in Sources */,
    31733177                                7CCE7EB81A411A7E00447C4C /* ContextMenuCanCopyURL.mm in Sources */,
    31743178                                37FB72971DB2E82F00E41BE4 /* ContextMenuDefaultItemsHaveTags.mm in Sources */,
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp

    r222462 r222602  
    5757    case ActionType::CSSDisplayNoneSelector:
    5858        return os << "ActionType::CSSDisplayNone";
     59    case ActionType::Notify:
     60        return os << "ActionType::Notify";
    5961    case ActionType::IgnorePreviousRules:
    6062        return os << "ActionType::IgnorePreviousRules";
     
    98100    }
    99101
     102private:
    100103    void writeSource(const String&) final { }
    101104
     
    138141    }
    139142
    140 private:
    141143    CompiledContentExtensionData& m_data;
    142144    bool finalized { false };
     
    145147class InMemoryCompiledContentExtension : public ContentExtensions::CompiledContentExtension {
    146148public:
    147     static Ref<InMemoryCompiledContentExtension> createFromFilter(String&& filter)
     149    static Ref<InMemoryCompiledContentExtension> create(String&& filter)
    148150    {
    149151        CompiledContentExtensionData extensionData;
    150152        InMemoryContentExtensionCompilationClient client(extensionData);
    151153        auto compilerError = ContentExtensions::compileRuleList(client, WTFMove(filter));
    152         if (compilerError) {
    153             // Compiling should always succeed here. We have other tests for compile failures.
    154             EXPECT_TRUE(false);
    155         }
    156 
    157         return InMemoryCompiledContentExtension::create(WTFMove(extensionData));
     154
     155        // Compiling should always succeed here. We have other tests for compile failures.
     156        EXPECT_FALSE(compilerError);
     157
     158        return adoptRef(*new InMemoryCompiledContentExtension(WTFMove(extensionData)));
    158159    }
    159160
    160     static Ref<InMemoryCompiledContentExtension> create(CompiledContentExtensionData&& data)
    161     {
    162         return adoptRef(*new InMemoryCompiledContentExtension(WTFMove(data)));
    163     }
    164 
    165     virtual ~InMemoryCompiledContentExtension()
    166     {
    167     }
    168 
     161    const CompiledContentExtensionData& data() { return m_data; };
     162
     163private:
    169164    const ContentExtensions::SerializedActionByte* actions() const final { return m_data.actions.data(); }
    170165    unsigned actionsLength() const final { return m_data.actions.size(); }
     
    177172    bool conditionsApplyOnlyToDomain() const final { return m_data.conditionsApplyOnlyToDomain; }
    178173
    179 private:
    180174    InMemoryCompiledContentExtension(CompiledContentExtensionData&& data)
    181175        : m_data(WTFMove(data))
    182     {
    183     }
     176    { }
    184177
    185178    CompiledContentExtensionData m_data;
     
    212205{
    213206    AtomicString::init();
    214     auto extension = InMemoryCompiledContentExtension::createFromFilter(json);
     207    auto extension = InMemoryCompiledContentExtension::create(json);
    215208    ContentExtensions::ContentExtensionsBackend backend;
    216209    backend.addContentExtension("testFilter", WTFMove(extension));
     
    857850TEST_F(ContentExtensionTest, MultipleExtensions)
    858851{
    859     auto extension1 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}}]");
    860     auto extension2 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}}]");
     852    auto extension1 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}}]");
     853    auto extension2 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}}]");
    861854    ContentExtensions::ContentExtensionsBackend backend;
    862855    backend.addContentExtension("testFilter1", WTFMove(extension1));
     
    869862    testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies/block_load.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad }, 2);
    870863   
    871     auto ignoreExtension1 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}},"
     864    auto ignoreExtension1 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}},"
    872865        "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore1\"}}]");
    873     auto ignoreExtension2 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}},"
     866    auto ignoreExtension2 = InMemoryCompiledContentExtension::create("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}},"
    874867        "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore2\"}}]");
    875868    ContentExtensions::ContentExtensionsBackend backendWithIgnore;
     
    883876    testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore2.html"), { }, 1);
    884877    testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/block_cookies/ignore1/ignore2.html"), { }, 0);
     878}
     879
     880static bool actionsEqual(const std::pair<Vector<WebCore::ContentExtensions::Action>, Vector<String>>& actual, Vector<WebCore::ContentExtensions::Action>&& expected, bool ignorePreviousRules = false)
     881{
     882    if (ignorePreviousRules) {
     883        if (actual.second.size())
     884            return false;
     885    } else {
     886        if (actual.second.size() != 1)
     887            return false;
     888        if (actual.second[0] != "testFilter")
     889            return false;
     890    }
     891
     892    if (actual.first.size() != expected.size())
     893        return false;
     894    for (size_t i = 0; i < expected.size(); ++i) {
     895        if (actual.first[i].type() != expected[i].type())
     896            return false;
     897        if (actual.first[i].stringArgument() != expected[i].stringArgument())
     898            return false;
     899    }
     900    return true;
     901}
     902
     903static const char* jsonWithStringsToCombine = "["
     904    "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\"}},"
     905    "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\"}},"
     906    "{\"action\":{\"type\":\"notify\",\"notification\":\"BBB\"},\"trigger\":{\"url-filter\":\"B\"}},"
     907    "{\"action\":{\"type\":\"css-display-none\",\"selector\":\"CCC\"},\"trigger\":{\"url-filter\":\"C\"}},"
     908    "{\"action\":{\"type\":\"css-display-none\",\"selector\":\"selectorCombinedWithC\"},\"trigger\":{\"url-filter\":\"C\"}},"
     909    "{\"action\":{\"type\":\"css-display-none\",\"selector\":\"DDD\"},\"trigger\":{\"url-filter\":\"D\"}},"
     910    "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"E\"}},"
     911    "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"F\"}},"
     912    "{\"action\":{\"type\":\"notify\",\"notification\":\"GGG\"},\"trigger\":{\"url-filter\":\"G\"}},"
     913    "{\"action\":{\"type\":\"notify\",\"notification\":\"GGG\"},\"trigger\":{\"url-filter\":\"I\"}},"
     914    "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"J\"}},"
     915    "{\"action\":{\"type\":\"notify\",\"notification\":\"GGG\"},\"trigger\":{\"url-filter\":\"K\"}}"
     916"]";
     917
     918TEST_F(ContentExtensionTest, StringParameters)
     919{
     920    auto backend1 = makeBackend("[{\"action\":{\"type\":\"notify\",\"notification\":\"testnotification\"},\"trigger\":{\"url-filter\":\"matches\"}}]");
     921    ASSERT_TRUE(actionsEqual(backend1.actionsForResourceLoad(mainDocumentRequest("test:///matches")), {{ ContentExtensions::ActionType::Notify, "testnotification" }}));
     922
     923    auto backend2 = makeBackend(jsonWithStringsToCombine);
     924    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://A")), {{ ContentExtensions::ActionType::Notify, "AAA" }}));
     925    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://B")), {{ ContentExtensions::ActionType::Notify, "BBB" }}));
     926    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://C")), {{ ContentExtensions::ActionType::CSSDisplayNoneSelector, "CCC,selectorCombinedWithC" }}));
     927    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://D")), {{ ContentExtensions::ActionType::CSSDisplayNoneSelector, "DDD" }}));
     928    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://E")), { }, true));
     929    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://F")), { ContentExtensions::ActionType::BlockLoad }));
     930    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://G")), {{ ContentExtensions::ActionType::Notify, "GGG" }}));
     931    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://GIK")), {{ ContentExtensions::ActionType::Notify, "GGG" }}));
     932    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://AJ")), {
     933        { ContentExtensions::ActionType::Notify, "AAA" },
     934        { ContentExtensions::ActionType::Notify, "AAA" } // ignore-previous-rules makes the AAA actions need to be unique.
     935    }));
     936    // FIXME: Add a test that matches actions with AAA with ignore-previous-rules between them and makes sure we only get one notification.
     937    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://AE")), { }, true));
     938    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://ABCDE")), { }, true));
     939    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://ABCDEFG")), {
     940        { ContentExtensions::ActionType::Notify, "GGG" },
     941        { ContentExtensions::ActionType::BlockLoad }
     942    }, true));
     943    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://FG")), {
     944        { ContentExtensions::ActionType::Notify, "GGG" },
     945        { ContentExtensions::ActionType::BlockLoad }
     946    }));
     947    ASSERT_TRUE(actionsEqual(backend2.actionsForResourceLoad(mainDocumentRequest("http://EFG")), {
     948        { ContentExtensions::ActionType::Notify, "GGG" },
     949        { ContentExtensions::ActionType::BlockLoad }
     950    }, true));
     951}
     952
     953template<typename T, size_t cStringLength>
     954static int sequenceInstances(const Vector<T> vector, const char (&sequence)[cStringLength])
     955{
     956    static_assert(sizeof(T) == sizeof(char), "sequenceInstances should only be used for various byte vectors.");
     957
     958    size_t sequenceLength = cStringLength - 1;
     959    size_t instances = 0;
     960    for (size_t i = 0; i <= vector.size() - sequenceLength; ++i) {
     961        for (size_t j = 0; j < sequenceLength; j++) {
     962            if (vector[i + j] != sequence[j])
     963                break;
     964            if (j == sequenceLength - 1)
     965                instances++;
     966        }
     967    }
     968    return instances;
     969}
     970
     971TEST_F(ContentExtensionTest, StringCombining)
     972{
     973    auto extension = InMemoryCompiledContentExtension::create(jsonWithStringsToCombine);
     974    const auto& data = extension->data();
     975
     976    ASSERT_EQ(sequenceInstances(data.actions, "AAA"), 2);
     977    ASSERT_EQ(sequenceInstances(data.actions, "GGG"), 1);
     978
     979    ASSERT_EQ(data.actions.size(), 78u);
     980    ASSERT_EQ(data.filtersWithoutConditions.size(),  313u);
     981    ASSERT_EQ(data.filtersWithConditions.size(),  5u);
     982    ASSERT_EQ(data.topURLFilters.size(),  5u);
     983    ASSERT_FALSE(data.conditionsApplyOnlyToDomain);
     984
     985    auto extensionWithFlags = InMemoryCompiledContentExtension::create("["
     986        "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\"}},"
     987        "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"C\"}},"
     988        "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\",\"resource-type\":[\"document\"]}},"
     989        "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"A\",\"resource-type\":[\"document\",\"font\"]}},"
     990        "{\"action\":{\"type\":\"notify\",\"notification\":\"AAA\"},\"trigger\":{\"url-filter\":\"B\",\"resource-type\":[\"document\"]}}"
     991    "]");
     992    ASSERT_EQ(sequenceInstances(extensionWithFlags->data().actions, "AAA"), 3); // There are 3 sets of unique flags for AAA actions.
    885993}
    886994
     
    13771485    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":false}}]",
    13781486        ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
     1487   
     1488    checkCompilerError("[{\"action\":{\"type\":\"notify\"},\"trigger\":{\"url-filter\":\".*\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidNotification);
     1489    checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":5},\"trigger\":{\"url-filter\":\".*\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidNotification);
     1490    checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":[]},\"trigger\":{\"url-filter\":\".*\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidNotification);
     1491    checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":\"here's my notification\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
     1492    checkCompilerError("[{\"action\":{\"type\":\"notify\",\"notification\":\"\\u1234\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
    13791493   
    13801494    StringBuilder rules;
Note: See TracChangeset for help on using the changeset viewer.