Title: [182168] trunk
Revision
182168
Author
[email protected]
Date
2015-03-30 17:48:30 -0700 (Mon, 30 Mar 2015)

Log Message

[Content Extensions] Correctly handle regular expressions matching everything
https://bugs.webkit.org/show_bug.cgi?id=143235

Reviewed by Benjamin Poulain.

Source/WebCore:

Test: http/tests/contentextensions/whitelist.html

* contentextensions/CompiledContentExtension.cpp:
(WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors):
Global actions can have non-css actions.  Only put the selectors into the list of selectors.
* contentextensions/ContentExtensionCompiler.cpp:
(WebCore::ContentExtensions::serializeSelector):
(WebCore::ContentExtensions::serializeActions):
Merge sequential css selectors with identical triggers (usually .*) into one action to reduce the number of actions.
(WebCore::ContentExtensions::compileRuleList):
Fail if a regular _expression_ matches everything after ignore-previous-rules.
* contentextensions/ContentExtensionError.cpp:
(WebCore::ContentExtensions::contentExtensionErrorCategory):
* contentextensions/ContentExtensionError.h:
Add more failure cases.
* contentextensions/ContentExtensionRule.h:
(WebCore::ContentExtensions::Trigger::operator==):
Allow comparing of Triggers to determine if sequential triggers are equal.
* contentextensions/ContentExtensionsBackend.cpp:
(WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad):
Put non-css actions that match everything into the list of actions if ignore-previous-rules was not hit.
These actions will be out of order, but order only matters when determining if ignore-previous-rules, and this case is handled correctly.
* contentextensions/DFABytecodeInterpreter.cpp:
(WebCore::ContentExtensions::DFABytecodeInterpreter::actionsFromDFARoot):
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
Added an assertion that all actions that match everything should be in the first DFA root.
We should catch them all with URLFilterParser::MatchesEverything.

Tools:

* TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
(TestWebKitAPI::checkCompilerError):
(TestWebKitAPI::TEST_F):
Test ContentExtensionErrors.

LayoutTests:

* http/tests/contentextensions/css-display-none.html:
* http/tests/contentextensions/css-display-none.html.json:
Test multiple selectors with triggers that match everything.
* http/tests/contentextensions/whitelist-expected.txt: Added.
* http/tests/contentextensions/whitelist.html: Added.
* http/tests/contentextensions/whitelist.html.json: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (182167 => 182168)


--- trunk/LayoutTests/ChangeLog	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/LayoutTests/ChangeLog	2015-03-31 00:48:30 UTC (rev 182168)
@@ -1,3 +1,17 @@
+2015-03-30  Alex Christensen  <[email protected]>
+
+        [Content Extensions] Correctly handle regular expressions matching everything
+        https://bugs.webkit.org/show_bug.cgi?id=143235
+
+        Reviewed by Benjamin Poulain.
+
+        * http/tests/contentextensions/css-display-none.html:
+        * http/tests/contentextensions/css-display-none.html.json:
+        Test multiple selectors with triggers that match everything.
+        * http/tests/contentextensions/whitelist-expected.txt: Added.
+        * http/tests/contentextensions/whitelist.html: Added.
+        * http/tests/contentextensions/whitelist.html.json: Added.
+
 2015-03-30  Mark Lam  <[email protected]>
 
         REGRESSION (r181993): inspector-protocol/debugger/setBreakpoint-dfg-and-modify-local.html crashes.

Modified: trunk/LayoutTests/http/tests/contentextensions/css-display-none.html (182167 => 182168)


--- trunk/LayoutTests/http/tests/contentextensions/css-display-none.html	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/LayoutTests/http/tests/contentextensions/css-display-none.html	2015-03-31 00:48:30 UTC (rev 182168)
@@ -2,7 +2,8 @@
 <meta charset="UTF-8"></meta>
 </head>
 <body>
-<p class="hidden_global">This text should not be visible once the global css selector is applied.</p>
+<p class="hidden_global1">This text should not be visible once the global css selector is applied.</p>
+<p class="hidden_global2">This text should not be visible once the global css selector is applied.</p>
 <p class="hidden">This text should not be visible once the particular css selector is applied.</p>
 <p class="hidden_Ž">This text should not be visible once the particular css selector with non-ascii characters is applied.</p>
 <p class="not_hidden">This text should be visible.</p>

Modified: trunk/LayoutTests/http/tests/contentextensions/css-display-none.html.json (182167 => 182168)


--- trunk/LayoutTests/http/tests/contentextensions/css-display-none.html.json	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/LayoutTests/http/tests/contentextensions/css-display-none.html.json	2015-03-31 00:48:30 UTC (rev 182168)
@@ -20,10 +20,27 @@
     {
         "action": {
             "type": "css-display-none",
-            "selector": ".hidden_global"
+            "selector": ".hidden_global1"
         },
         "trigger": {
             "url-filter": ".*"
         }
+    },
+    {
+        "action": {
+            "type": "css-display-none",
+            "selector": ".hidden_global2"
+        },
+        "trigger": {
+            "url-filter": ".*"
+        }
+    },
+    {
+        "action": {
+            "type": "ignore-previous-rules"
+        },
+        "trigger": {
+            "url-filter": "never_used"
+        }
     }
 ]

Added: trunk/LayoutTests/http/tests/contentextensions/whitelist-expected.txt (0 => 182168)


--- trunk/LayoutTests/http/tests/contentextensions/whitelist-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/contentextensions/whitelist-expected.txt	2015-03-31 00:48:30 UTC (rev 182168)
@@ -0,0 +1,7 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderText {#text} at (0,0) size 192x18
+        text run at (0,0) width 192: "This should load successfully."

Added: trunk/LayoutTests/http/tests/contentextensions/whitelist.html (0 => 182168)


--- trunk/LayoutTests/http/tests/contentextensions/whitelist.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/contentextensions/whitelist.html	2015-03-31 00:48:30 UTC (rev 182168)
@@ -0,0 +1 @@
+This should load successfully.

Added: trunk/LayoutTests/http/tests/contentextensions/whitelist.html.json (0 => 182168)


--- trunk/LayoutTests/http/tests/contentextensions/whitelist.html.json	                        (rev 0)
+++ trunk/LayoutTests/http/tests/contentextensions/whitelist.html.json	2015-03-31 00:48:30 UTC (rev 182168)
@@ -0,0 +1,18 @@
+[
+    {
+        "action": {
+            "type": "block"
+        },
+        "trigger": {
+            "url-filter": ".*"
+        }
+    },
+    {
+        "action": {
+            "type": "ignore-previous-rules"
+        },
+        "trigger": {
+            "url-filter": "whitelist"
+        }
+    }
+]

Modified: trunk/Source/WebCore/ChangeLog (182167 => 182168)


--- trunk/Source/WebCore/ChangeLog	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/ChangeLog	2015-03-31 00:48:30 UTC (rev 182168)
@@ -1,3 +1,38 @@
+2015-03-30  Alex Christensen  <[email protected]>
+
+        [Content Extensions] Correctly handle regular expressions matching everything
+        https://bugs.webkit.org/show_bug.cgi?id=143235
+
+        Reviewed by Benjamin Poulain.
+
+        Test: http/tests/contentextensions/whitelist.html
+
+        * contentextensions/CompiledContentExtension.cpp:
+        (WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors):
+        Global actions can have non-css actions.  Only put the selectors into the list of selectors.
+        * contentextensions/ContentExtensionCompiler.cpp:
+        (WebCore::ContentExtensions::serializeSelector):
+        (WebCore::ContentExtensions::serializeActions):
+        Merge sequential css selectors with identical triggers (usually .*) into one action to reduce the number of actions.
+        (WebCore::ContentExtensions::compileRuleList):
+        Fail if a regular _expression_ matches everything after ignore-previous-rules.
+        * contentextensions/ContentExtensionError.cpp:
+        (WebCore::ContentExtensions::contentExtensionErrorCategory):
+        * contentextensions/ContentExtensionError.h:
+        Add more failure cases.
+        * contentextensions/ContentExtensionRule.h:
+        (WebCore::ContentExtensions::Trigger::operator==):
+        Allow comparing of Triggers to determine if sequential triggers are equal.
+        * contentextensions/ContentExtensionsBackend.cpp:
+        (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad):
+        Put non-css actions that match everything into the list of actions if ignore-previous-rules was not hit.
+        These actions will be out of order, but order only matters when determining if ignore-previous-rules, and this case is handled correctly.
+        * contentextensions/DFABytecodeInterpreter.cpp:
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::actionsFromDFARoot):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
+        Added an assertion that all actions that match everything should be in the first DFA root.
+        We should catch them all with URLFilterParser::MatchesEverything.
+
 2015-03-30  Myles C. Maxfield  <[email protected]>
 
         Allow building on Windows without Cygwin

Modified: trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp	2015-03-31 00:48:30 UTC (rev 182168)
@@ -47,8 +47,7 @@
     
     Vector<String> selectors;
     for (Action& action : globalActions) {
-        ASSERT(action.type() == ActionType::CSSDisplayNoneSelector);
-        if (action.stringArgument().length())
+        if (action.type() == ActionType::CSSDisplayNoneSelector)
             selectors.append(action.stringArgument());
     }
     

Modified: trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp	2015-03-31 00:48:30 UTC (rev 182168)
@@ -41,10 +41,33 @@
 #include <wtf/CurrentTime.h>
 #include <wtf/DataLog.h>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 namespace ContentExtensions {
 
+static void serializeSelector(Vector<SerializedActionByte>& actions, const String& selector)
+{
+    // Append action type (1 byte).
+    actions.append(static_cast<SerializedActionByte>(ActionType::CSSDisplayNoneSelector));
+    // Append Selector length (4 bytes).
+    unsigned selectorLength = selector.length();
+    actions.resize(actions.size() + sizeof(unsigned));
+    *reinterpret_cast<unsigned*>(&actions[actions.size() - sizeof(unsigned)]) = selectorLength;
+    bool wideCharacters = !selector.is8Bit();
+    actions.append(wideCharacters);
+    // Append Selector.
+    if (wideCharacters) {
+        unsigned startIndex = actions.size();
+        actions.resize(actions.size() + sizeof(UChar) * selectorLength);
+        for (unsigned i = 0; i < selectorLength; ++i)
+            *reinterpret_cast<UChar*>(&actions[startIndex + i * sizeof(UChar)]) = selector[i];
+    } else {
+        for (unsigned i = 0; i < selectorLength; ++i)
+            actions.append(selector[i]);
+    }
+}
+    
 static Vector<unsigned> serializeActions(const Vector<ContentExtensionRule>& ruleList, Vector<SerializedActionByte>& actions)
 {
     ASSERT(!actions.size());
@@ -54,14 +77,33 @@
     for (unsigned ruleIndex = 0; ruleIndex < ruleList.size(); ++ruleIndex) {
         const ContentExtensionRule& rule = ruleList[ruleIndex];
         
+        // Consolidate css selectors with identical triggers.
+        if (rule.action().type() == ActionType::CSSDisplayNoneSelector) {
+            StringBuilder selector;
+            selector.append(rule.action().stringArgument());
+            actionLocations.append(actions.size());
+            for (unsigned i = ruleIndex + 1; i < ruleList.size(); i++) {
+                if (rule.trigger() == ruleList[i].trigger() && ruleList[i].action().type() == ActionType::CSSDisplayNoneSelector) {
+                    actionLocations.append(actions.size());
+                    ruleIndex++;
+                    selector.append(',');
+                    selector.append(ruleList[i].action().stringArgument());
+                } else
+                    break;
+            }
+            serializeSelector(actions, selector.toString());
+            continue;
+        }
+        
         // Identical sequential actions should not be rewritten.
         if (ruleIndex && rule.action() == ruleList[ruleIndex - 1].action()) {
             actionLocations.append(actionLocations[ruleIndex - 1]);
             continue;
         }
+
         actionLocations.append(actions.size());
-        
         switch (rule.action().type()) {
+        case ActionType::CSSDisplayNoneSelector:
         case ActionType::CSSDisplayNoneStyleSheet:
         case ActionType::InvalidAction:
             RELEASE_ASSERT_NOT_REACHED();
@@ -71,30 +113,7 @@
         case ActionType::IgnorePreviousRules:
             actions.append(static_cast<SerializedActionByte>(rule.action().type()));
             break;
-
-        case ActionType::CSSDisplayNoneSelector: {
-            const String& selector = rule.action().stringArgument();
-            // Append action type (1 byte).
-            actions.append(static_cast<SerializedActionByte>(ActionType::CSSDisplayNoneSelector));
-            // Append Selector length (4 bytes).
-            unsigned selectorLength = selector.length();
-            actions.resize(actions.size() + sizeof(unsigned));
-            *reinterpret_cast<unsigned*>(&actions[actions.size() - sizeof(unsigned)]) = selectorLength;
-            bool wideCharacters = !selector.is8Bit();
-            actions.append(wideCharacters);
-            // Append Selector.
-            if (wideCharacters) {
-                for (unsigned i = 0; i < selectorLength; i++) {
-                    actions.resize(actions.size() + sizeof(UChar));
-                    *reinterpret_cast<UChar*>(&actions[actions.size() - sizeof(UChar)]) = selector[i];
-                }
-            } else {
-                for (unsigned i = 0; i < selectorLength; i++)
-                    actions.append(selector[i]);
-            }
-            break;
         }
-        }
     }
     return actionLocations;
 }
@@ -117,7 +136,7 @@
 
     Vector<NFA> nfas;
     nfas.append(NFA());
-    bool nonUniversalActionSeen = false;
+    bool ignorePreviousRulesSeen = false;
     for (unsigned ruleIndex = 0; ruleIndex < parsedRuleList.size(); ++ruleIndex) {
 
         // FIXME: Tune this better and adjust ContentExtensionTest.MultiDFA accordingly.
@@ -135,16 +154,18 @@
         URLFilterParser::ParseStatus status = urlFilterParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocationAndFlags);
 
         if (status == URLFilterParser::MatchesEverything) {
-            if (nonUniversalActionSeen)
-                dataLogF("Trigger matching everything found not at beginning.  This may cause incorrect behavior with ignore-previous-rules");
+            if (ignorePreviousRulesSeen)
+                return ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules;
             universalActionLocations.append(actionLocationAndFlags);
-        } else
-            nonUniversalActionSeen = true;
+        }
         
         if (status != URLFilterParser::Ok && status != URLFilterParser::MatchesEverything) {
             dataLogF("Error while parsing %s: %s\n", trigger.urlFilter.utf8().data(), URLFilterParser::statusString(status).utf8().data());
-            continue;
+            return ContentExtensionError::JSONInvalidRegex;
         }
+        
+        if (contentExtensionRule.action().type() == ActionType::IgnorePreviousRules)
+            ignorePreviousRulesSeen = true;
     }
 
 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
@@ -172,6 +193,7 @@
         dfa.debugPrintDot();
 #endif
 
+        ASSERT_WITH_MESSAGE(!dfa.nodeAt(dfa.root()).actions.size(), "All actions on the DFA root should come from regular expressions that match everything.");
         if (!i) {
             // Put all the universal actions on the first DFA.
             for (uint64_t actionLocation : universalActionLocations)

Modified: trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp	2015-03-31 00:48:30 UTC (rev 182168)
@@ -73,6 +73,10 @@
                 return "Invalid action type.";
             case ContentExtensionError::JSONInvalidCSSDisplayNoneActionType:
                 return "Invalid css-display-none action type. Requires a selector.";
+            case ContentExtensionError::JSONInvalidRegex:
+                return "Invalid or unsupported regular _expression_.";
+            case ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules:
+                return "Regular expressions that match everything are only allowed before the first ignore-previous-rules.";
             }
 
             return std::string();

Modified: trunk/Source/WebCore/contentextensions/ContentExtensionError.h (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/ContentExtensionError.h	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionError.h	2015-03-31 00:48:30 UTC (rev 182168)
@@ -53,6 +53,9 @@
     JSONInvalidAction,
     JSONInvalidActionType,
     JSONInvalidCSSDisplayNoneActionType,
+    JSONInvalidRegex,
+    
+    RegexMatchesEverythingAfterIgnorePreviousRules,
 };
 
 const std::error_category& contentExtensionErrorCategory();

Modified: trunk/Source/WebCore/contentextensions/ContentExtensionRule.h (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/ContentExtensionRule.h	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionRule.h	2015-03-31 00:48:30 UTC (rev 182168)
@@ -45,6 +45,12 @@
     String urlFilter;
     bool urlFilterIsCaseSensitive { false };
     ResourceFlags flags { 0 };
+    bool operator==(const Trigger& other) const
+    {
+        return urlFilter == other.urlFilter
+            && urlFilterIsCaseSensitive == other.urlFilterIsCaseSensitive
+            && flags == other.flags;
+    }
 };
     
 struct Action {

Modified: trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp	2015-03-31 00:48:30 UTC (rev 182168)
@@ -104,8 +104,17 @@
                 finalActions.append(action);
             }
         }
-        if (!sawIgnorePreviousRules)
+        if (!sawIgnorePreviousRules) {
+            DFABytecodeInterpreter::Actions universalActions = interpreter.actionsFromDFARoot();
+            for (auto actionLocation : universalActions) {
+                Action action = "" actionsLength, actionLocation);
+                
+                // CSS selectors were already compiled into a stylesheet using globalDisplayNoneSelectors.
+                if (action.type() != ActionType::CSSDisplayNoneSelector)
+                    finalActions.append(action);
+            }
             finalActions.append(Action(ActionType::CSSDisplayNoneStyleSheet, contentExtension->identifier()));
+        }
     }
     return finalActions;
 }

Modified: trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp (182167 => 182168)


--- trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp	2015-03-31 00:48:30 UTC (rev 182168)
@@ -47,6 +47,7 @@
 
     // Skip first DFA header. All universal actions are in the first DFA root.
     unsigned programCounter = sizeof(unsigned);
+
     while (static_cast<DFABytecodeInstruction>(m_bytecode[programCounter]) == DFABytecodeInstruction::AppendAction) {
         universalActionLocations.add(static_cast<uint64_t>(getBits<unsigned>(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode))));
         programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
@@ -69,10 +70,11 @@
         unsigned dfaBytecodeLength = getBits<unsigned>(m_bytecode, m_bytecodeLength, programCounter);
         programCounter += sizeof(unsigned);
 
-        // Skip the universal actions.
-        // FIXME: Replace AppendAction with AppendActions to make this just one jump and make sure there aren't universal actions with flags.
-        while (static_cast<DFABytecodeInstruction>(m_bytecode[programCounter]) == DFABytecodeInstruction::AppendAction)
+        // Skip the actions on the DFA root. These are accessed via actionsFromDFARoot.
+        while (static_cast<DFABytecodeInstruction>(m_bytecode[programCounter]) == DFABytecodeInstruction::AppendAction) {
+            ASSERT_WITH_MESSAGE(!dfaStart, "Triggers that match everything should only be in the first DFA.");
             programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
+        }
         
         // Interpret the bytecode from this DFA.
         // This should always terminate if interpreting correctly compiled bytecode.

Modified: trunk/Tools/ChangeLog (182167 => 182168)


--- trunk/Tools/ChangeLog	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Tools/ChangeLog	2015-03-31 00:48:30 UTC (rev 182168)
@@ -1,3 +1,15 @@
+2015-03-30  Alex Christensen  <[email protected]>
+
+        [Content Extensions] Correctly handle regular expressions matching everything
+        https://bugs.webkit.org/show_bug.cgi?id=143235
+
+        Reviewed by Benjamin Poulain.
+
+        * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
+        (TestWebKitAPI::checkCompilerError):
+        (TestWebKitAPI::TEST_F):
+        Test ContentExtensionErrors.
+
 2015-03-30  Alexey Proskuryakov  <[email protected]>
 
         DumpRenderTree should set NSWindowDisplayWithRunLoopObserver

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp (182167 => 182168)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp	2015-03-31 00:43:49 UTC (rev 182167)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp	2015-03-31 00:48:30 UTC (rev 182168)
@@ -28,6 +28,7 @@
 #include "PlatformUtilities.h"
 #include <_javascript_Core/InitializeThreading.h>
 #include <WebCore/ContentExtensionCompiler.h>
+#include <WebCore/ContentExtensionError.h>
 #include <WebCore/ContentExtensionsBackend.h>
 #include <WebCore/NFA.h>
 #include <WebCore/ResourceLoadInfo.h>
@@ -573,6 +574,53 @@
     testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
 }
 
+void checkCompilerError(const char* json, ContentExtensions::ContentExtensionError expectedError)
+{
+    WebCore::ContentExtensions::CompiledContentExtensionData extensionData;
+    InMemoryContentExtensionCompilationClient client(extensionData);
+    std::error_code compilerError = ContentExtensions::compileRuleList(client, json);
+    EXPECT_EQ(compilerError.value(), static_cast<int>(expectedError));
+}
+
+TEST_F(ContentExtensionTest, InvalidJSON)
+{
+    checkCompilerError("[", ContentExtensions::ContentExtensionError::JSONInvalid);
+    checkCompilerError("123", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnObject);
+    checkCompilerError("{}", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnArray);
+    // FIXME: Add unit test for JSONInvalidRule if that is possible to hit.
+    checkCompilerError("[]", ContentExtensions::ContentExtensionError::JSONContainsNoRules);
+
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":5}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidTrigger);
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"\"}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":{}}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
+
+    // FIXME: Add unit test for JSONInvalidObjectInTriggerFlagsArray if that is possible to hit.
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":{}}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"invalid\"]}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":{}}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[\"invalid\"]}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+
+    checkCompilerError("[{\"action\":5,\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidAction);
+    checkCompilerError("[{\"action\":{\"type\":\"invalid\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidActionType);
+    checkCompilerError("[{\"action\":{\"type\":\"css-display-none\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidCSSDisplayNoneActionType);
+
+    checkCompilerError("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"webkit.org\"}},"
+        "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]",
+        ContentExtensions::ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules);
+    checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[\"}}]",
+        ContentExtensions::ContentExtensionError::JSONInvalidRegex);
+}
+
 static void testPatternStatus(String pattern, ContentExtensions::URLFilterParser::ParseStatus status)
 {
     ContentExtensions::NFA nfa;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to