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

Changeset 181726 in webkit


Ignore:
Timestamp:
Mar 18, 2015, 9:57:20 PM (11 years ago)
Author:
commit-queue@webkit.org
Message:

[ContentExtensions] Prepare for compiling stylesheets of selectors to be used on every page.
https://bugs.webkit.org/show_bug.cgi?id=142799

Patch by Alex Christensen <achristensen@webkit.org> on 2015-03-18
Reviewed by Brady Eidson.

Source/WebCore:

  • WebCore.xcodeproj/project.pbxproj:

Make private headers to use with API tests.

  • contentextensions/CompiledContentExtension.cpp:

(WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors):

  • contentextensions/CompiledContentExtension.h:

Added method to get only the selectors from the root of the DFA, which apply to all URLs.

  • contentextensions/ContentExtensionCompiler.cpp:

(WebCore::ContentExtensions::compileRuleList):
Added checking if the trigger will match everything.
These actions can be put directly on the root of the DFA without adding extra epsilon transitions to the NFA.

  • contentextensions/DFA.h:

(WebCore::ContentExtensions::DFA::nodeAt):

  • contentextensions/DFABytecodeInterpreter.cpp:

(WebCore::ContentExtensions::DFABytecodeInterpreter::actionsFromDFARoot):
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):

  • contentextensions/DFABytecodeInterpreter.h:
  • contentextensions/NFA.h:
  • contentextensions/URLFilterParser.cpp:

(WebCore::ContentExtensions::Term::quantifier):
Sink terms to a vector then add nodes to NFA when finalizing after checking for regexes that match everything.
(WebCore::ContentExtensions::GraphBuilder::GraphBuilder):
(WebCore::ContentExtensions::GraphBuilder::finalize):
(WebCore::ContentExtensions::GraphBuilder::parseStatus):
(WebCore::ContentExtensions::GraphBuilder::atomPatternCharacter):
(WebCore::ContentExtensions::GraphBuilder::atomBuiltInCharacterClass):
(WebCore::ContentExtensions::GraphBuilder::quantifyAtom):
(WebCore::ContentExtensions::GraphBuilder::atomBackReference):
(WebCore::ContentExtensions::GraphBuilder::assertionBOL):
(WebCore::ContentExtensions::GraphBuilder::assertionWordBoundary):
(WebCore::ContentExtensions::GraphBuilder::atomCharacterClassAtom):
(WebCore::ContentExtensions::GraphBuilder::atomCharacterClassRange):
(WebCore::ContentExtensions::GraphBuilder::atomCharacterClassBuiltIn):
(WebCore::ContentExtensions::GraphBuilder::atomParentheticalAssertionBegin):
(WebCore::ContentExtensions::GraphBuilder::disjunction):
(WebCore::ContentExtensions::GraphBuilder::hasError):
(WebCore::ContentExtensions::GraphBuilder::fail):
(WebCore::ContentExtensions::GraphBuilder::sinkFloatingTermIfNecessary):
(WebCore::ContentExtensions::URLFilterParser::addPattern):
(WebCore::ContentExtensions::URLFilterParser::statusString):
(WebCore::ContentExtensions::GraphBuilder::errorMessage): Deleted.

  • contentextensions/URLFilterParser.h:

Use an enum instead of strings for the status to avoid checking strings when we have a regex that matches everything.

Tools:

  • TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:

(TestWebKitAPI::testPattern):
(TestWebKitAPI::TEST_F):
Start testing regex failures.

Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r181725 r181726  
     12015-03-18  Alex Christensen  <achristensen@webkit.org>
     2
     3        [ContentExtensions] Prepare for compiling stylesheets of selectors to be used on every page.
     4        https://bugs.webkit.org/show_bug.cgi?id=142799
     5
     6        Reviewed by Brady Eidson.
     7
     8        * WebCore.xcodeproj/project.pbxproj:
     9        Make private headers to use with API tests.
     10        * contentextensions/CompiledContentExtension.cpp:
     11        (WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors):
     12        * contentextensions/CompiledContentExtension.h:
     13        Added method to get only the selectors from the root of the DFA, which apply to all URLs.
     14        * contentextensions/ContentExtensionCompiler.cpp:
     15        (WebCore::ContentExtensions::compileRuleList):
     16        Added checking if the trigger will match everything.
     17        These actions can be put directly on the root of the DFA without adding extra epsilon transitions to the NFA.
     18        * contentextensions/DFA.h:
     19        (WebCore::ContentExtensions::DFA::nodeAt):
     20        * contentextensions/DFABytecodeInterpreter.cpp:
     21        (WebCore::ContentExtensions::DFABytecodeInterpreter::actionsFromDFARoot):
     22        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
     23        * contentextensions/DFABytecodeInterpreter.h:
     24        * contentextensions/NFA.h:
     25        * contentextensions/URLFilterParser.cpp:
     26        (WebCore::ContentExtensions::Term::quantifier):
     27        Sink terms to a vector then add nodes to NFA when finalizing after checking for regexes that match everything.
     28        (WebCore::ContentExtensions::GraphBuilder::GraphBuilder):
     29        (WebCore::ContentExtensions::GraphBuilder::finalize):
     30        (WebCore::ContentExtensions::GraphBuilder::parseStatus):
     31        (WebCore::ContentExtensions::GraphBuilder::atomPatternCharacter):
     32        (WebCore::ContentExtensions::GraphBuilder::atomBuiltInCharacterClass):
     33        (WebCore::ContentExtensions::GraphBuilder::quantifyAtom):
     34        (WebCore::ContentExtensions::GraphBuilder::atomBackReference):
     35        (WebCore::ContentExtensions::GraphBuilder::assertionBOL):
     36        (WebCore::ContentExtensions::GraphBuilder::assertionWordBoundary):
     37        (WebCore::ContentExtensions::GraphBuilder::atomCharacterClassAtom):
     38        (WebCore::ContentExtensions::GraphBuilder::atomCharacterClassRange):
     39        (WebCore::ContentExtensions::GraphBuilder::atomCharacterClassBuiltIn):
     40        (WebCore::ContentExtensions::GraphBuilder::atomParentheticalAssertionBegin):
     41        (WebCore::ContentExtensions::GraphBuilder::disjunction):
     42        (WebCore::ContentExtensions::GraphBuilder::hasError):
     43        (WebCore::ContentExtensions::GraphBuilder::fail):
     44        (WebCore::ContentExtensions::GraphBuilder::sinkFloatingTermIfNecessary):
     45        (WebCore::ContentExtensions::URLFilterParser::addPattern):
     46        (WebCore::ContentExtensions::URLFilterParser::statusString):
     47        (WebCore::ContentExtensions::GraphBuilder::errorMessage): Deleted.
     48        * contentextensions/URLFilterParser.h:
     49        Use an enum instead of strings for the status to avoid checking strings when we have a regex that matches everything.
     50
    1512015-03-18  Yusuke Suzuki  <utatane.tea@gmail.com>
    252
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r181671 r181726  
    994994                2542F4DA1166C25A00E89A86 /* UserGestureIndicator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2542F4D81166C25A00E89A86 /* UserGestureIndicator.cpp */; };
    995995                2542F4DB1166C25A00E89A86 /* UserGestureIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2542F4D91166C25A00E89A86 /* UserGestureIndicator.h */; settings = {ATTRIBUTES = (Private, ); }; };
    996                 262391361A648CEE007251A3 /* ContentExtensionsDebugging.h in Headers */ = {isa = PBXBuildFile; fileRef = 262391351A648CEE007251A3 /* ContentExtensionsDebugging.h */; };
     996                262391361A648CEE007251A3 /* ContentExtensionsDebugging.h in Headers */ = {isa = PBXBuildFile; fileRef = 262391351A648CEE007251A3 /* ContentExtensionsDebugging.h */; settings = {ATTRIBUTES = (Private, ); }; };
    997997                26255F0018878DFF0006E1FD /* UserAgentIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26255EFF18878DFF0006E1FD /* UserAgentIOS.mm */; };
    998998                26255F0318878E110006E1FD /* UserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 26255F0118878E110006E1FD /* UserAgent.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    10091009                267726011A5B3AD9003C24DD /* NFAToDFA.h in Headers */ = {isa = PBXBuildFile; fileRef = 267725FB1A5B3AD9003C24DD /* NFAToDFA.h */; };
    10101010                267726041A5DF6F2003C24DD /* URLFilterParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267726021A5DF6F2003C24DD /* URLFilterParser.cpp */; };
    1011                 267726051A5DF6F2003C24DD /* URLFilterParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 267726031A5DF6F2003C24DD /* URLFilterParser.h */; };
     1011                267726051A5DF6F2003C24DD /* URLFilterParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 267726031A5DF6F2003C24DD /* URLFilterParser.h */; settings = {ATTRIBUTES = (Private, ); }; };
    10121012                269239961505E1AA009E57FC /* JSIDBVersionChangeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 269239921505E1AA009E57FC /* JSIDBVersionChangeEvent.h */; };
    1013                 269397221A4A412F00E8349D /* NFANode.h in Headers */ = {isa = PBXBuildFile; fileRef = 269397201A4A412F00E8349D /* NFANode.h */; };
    1014                 269397241A4A5B6400E8349D /* NFA.h in Headers */ = {isa = PBXBuildFile; fileRef = 269397231A4A5B6400E8349D /* NFA.h */; };
     1013                269397221A4A412F00E8349D /* NFANode.h in Headers */ = {isa = PBXBuildFile; fileRef = 269397201A4A412F00E8349D /* NFANode.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1014                269397241A4A5B6400E8349D /* NFA.h in Headers */ = {isa = PBXBuildFile; fileRef = 269397231A4A5B6400E8349D /* NFA.h */; settings = {ATTRIBUTES = (Private, ); }; };
    10151015                269397261A4A5FBD00E8349D /* NFA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 269397251A4A5FBD00E8349D /* NFA.cpp */; };
    10161016                26AA0F9E18D2A18B00419381 /* SelectorPseudoElementTypeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26AA0F9D18D2A18B00419381 /* SelectorPseudoElementTypeMap.cpp */; };
  • trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp

    r181200 r181726  
    2626#include "config.h"
    2727#include "CompiledContentExtension.h"
     28#include "DFABytecodeInterpreter.h"
    2829
    2930#if ENABLE(CONTENT_EXTENSIONS)
     
    3637}
    3738
     39Vector<String> CompiledContentExtension::globalDisplayNoneSelectors()
     40{
     41    DFABytecodeInterpreter interpreter(bytecode(), bytecodeLength());
     42    DFABytecodeInterpreter::Actions actionLocations = interpreter.actionsFromDFARoot();
     43   
     44    Vector<Action> globalActions;
     45    for (uint64_t actionLocation : actionLocations)
     46        globalActions.append(Action::deserialize(actions(), actionsLength(), static_cast<unsigned>(actionLocation)));
     47   
     48    Vector<String> selectors;
     49    for (Action& action : globalActions) {
     50        if (action.cssSelector().length())
     51            selectors.append(action.cssSelector());
     52    }
     53   
     54    return selectors;
     55}
     56   
    3857} // namespace ContentExtensions
    3958} // namespace WebCore
  • trunk/Source/WebCore/contentextensions/CompiledContentExtension.h

    r181200 r181726  
    4545    virtual const SerializedActionByte* actions() const = 0;
    4646    virtual unsigned actionsLength() const = 0;
     47    Vector<String> globalDisplayNoneSelectors();
    4748};
    4849
  • trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp

    r181421 r181726  
    109109    Vector<SerializedActionByte> actions;
    110110    Vector<unsigned> actionLocations = serializeActions(parsedRuleList, actions);
     111    Vector<uint64_t> universalActionLocations;
    111112
    112113    NFA nfa;
    113114    URLFilterParser urlFilterParser(nfa);
     115    bool nonUniversalActionSeen = false;
    114116    for (unsigned ruleIndex = 0; ruleIndex < parsedRuleList.size(); ++ruleIndex) {
    115117        const ContentExtensionRule& contentExtensionRule = parsedRuleList[ruleIndex];
     
    118120
    119121        // High bits are used for flags. This should match how they are used in DFABytecodeCompiler::compileNode.
    120         String error = urlFilterParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, (static_cast<uint64_t>(trigger.flags) << 32) | static_cast<uint64_t>(actionLocations[ruleIndex]));
     122        uint64_t actionLocationAndFlags =(static_cast<uint64_t>(trigger.flags) << 32) | static_cast<uint64_t>(actionLocations[ruleIndex]);
     123        URLFilterParser::ParseStatus status = urlFilterParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocationAndFlags);
    121124
    122         if (!error.isNull()) {
    123             dataLogF("Error while parsing %s: %s\n", trigger.urlFilter.utf8().data(), error.utf8().data());
     125        if (status == URLFilterParser::MatchesEverything) {
     126            if (nonUniversalActionSeen)
     127                dataLogF("Trigger matching everything found not at beginning.  This may cause incorrect behavior with ignore-previous-rules");
     128            universalActionLocations.append(actionLocationAndFlags);
     129        } else
     130            nonUniversalActionSeen = true;
     131       
     132        if (status != URLFilterParser::Ok && status != URLFilterParser::MatchesEverything) {
     133            dataLogF("Error while parsing %s: %s\n", trigger.urlFilter.utf8().data(), URLFilterParser::statusString(status).utf8().data());
    124134            continue;
    125135        }
     
    139149#endif
    140150
    141     const DFA dfa = NFAToDFA::convert(nfa);
     151    DFA dfa = NFAToDFA::convert(nfa);
     152    for (uint64_t actionLocation : universalActionLocations)
     153        dfa.nodeAt(dfa.root()).actions.append(actionLocation);
    142154
    143155#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
  • trunk/Source/WebCore/contentextensions/DFA.h

    r180769 r181726  
    4949    unsigned size() const { return m_nodes.size(); }
    5050    const DFANode& nodeAt(unsigned i) const { return m_nodes[i]; }
     51    DFANode& nodeAt(unsigned i) { return m_nodes[i]; }
    5152
    5253#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
  • trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp

    r181663 r181726  
    4141    return *reinterpret_cast<const IntType*>(&bytecode[index]);
    4242}
    43 
     43   
     44DFABytecodeInterpreter::Actions DFABytecodeInterpreter::actionsFromDFARoot()
     45{
     46    unsigned programCounter = 0;
     47    DFABytecodeInterpreter::Actions globalActionLocations;
     48    while (static_cast<DFABytecodeInstruction>(m_bytecode[programCounter]) == DFABytecodeInstruction::AppendAction) {
     49        globalActionLocations.add(static_cast<uint64_t>(getBits<unsigned>(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode))));
     50        programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
     51    }
     52    return globalActionLocations;
     53}
     54   
    4455DFABytecodeInterpreter::Actions DFABytecodeInterpreter::interpret(const CString& urlCString, uint16_t flags)
    4556{
     
    5162    bool urlIndexIsAfterEndOfString = false;
    5263    Actions actions;
     64   
     65    // FIXME: Skip the actions from the root once they are used through actionsFromDFARoot. Change AppendAction to AppendActions to make this faster.
    5366   
    5467    // This should always terminate if interpreting correctly compiled bytecode.
  • trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.h

    r181421 r181726  
    4949   
    5050    Actions interpret(const CString&, uint16_t flags);
     51    Actions actionsFromDFARoot();
    5152
    5253private:
  • trunk/Source/WebCore/contentextensions/NFA.h

    r178857 r181726  
    4343class NFA {
    4444public:
    45     NFA();
     45    WEBCORE_EXPORT NFA();
    4646    unsigned root() const { return m_root; }
    4747    unsigned createNode();
  • trunk/Source/WebCore/contentextensions/URLFilterParser.cpp

    r181405 r181726  
    3333#include <wtf/BitVector.h>
    3434#include <wtf/Deque.h>
     35#include <wtf/text/CString.h>
    3536
    3637namespace WebCore {
     
    175176        m_quantifier = quantifier;
    176177    }
     178    AtomQuantifier quantifier() const { return m_quantifier; }
    177179
    178180    unsigned generateGraph(NFA& nfa, uint64_t patternId, unsigned start) const
     
    429431        , m_subtreeEnd(nfa.root())
    430432        , m_lastPrefixTreeEntry(&prefixTreeRoot)
     433        , m_parseStatus(URLFilterParser::Ok)
    431434    {
    432435    }
     
    439442        sinkFloatingTermIfNecessary();
    440443
     444        // Check to see if there are any terms without ? or *.
     445        bool matchesEverything = true;
     446        for (const auto& term : m_sunkTerms) {
     447            if (term.quantifier() == AtomQuantifier::One || term.quantifier() == AtomQuantifier::OneOrMore) {
     448                matchesEverything = false;
     449                break;
     450            }
     451        }
     452        if (matchesEverything)
     453            fail(URLFilterParser::MatchesEverything);
     454
     455        for (const auto& term : m_sunkTerms) {
     456            ASSERT(m_lastPrefixTreeEntry);
     457            auto nextEntry = m_lastPrefixTreeEntry->nextPattern.find(term);
     458            if (nextEntry != m_lastPrefixTreeEntry->nextPattern.end()) {
     459                m_lastPrefixTreeEntry = nextEntry->value.get();
     460                m_nfa.addRuleId(m_lastPrefixTreeEntry->nfaNode, m_patternId);
     461            } else {
     462                std::unique_ptr<PrefixTreeEntry> nextPrefixTreeEntry = std::make_unique<PrefixTreeEntry>();
     463               
     464                unsigned newEnd = term.generateGraph(m_nfa, m_patternId, m_lastPrefixTreeEntry->nfaNode);
     465                nextPrefixTreeEntry->nfaNode = newEnd;
     466               
     467                auto addResult = m_lastPrefixTreeEntry->nextPattern.set(term, WTF::move(nextPrefixTreeEntry));
     468                ASSERT(addResult.isNewEntry);
     469               
     470                if (!m_newPrefixSubtreeRoot) {
     471                    m_newPrefixSubtreeRoot = m_lastPrefixTreeEntry;
     472                    m_newPrefixStaringPoint = term;
     473                }
     474               
     475                m_lastPrefixTreeEntry = addResult.iterator->value.get();
     476            }
     477            m_subtreeEnd = m_lastPrefixTreeEntry->nfaNode;
     478        }
     479       
    441480        if (!m_openGroups.isEmpty()) {
    442             fail(ASCIILiteral("The expression has unclosed groups."));
     481            fail(URLFilterParser::UnclosedGroups);
    443482            return;
    444483        }
     
    447486            m_nfa.setFinal(m_subtreeEnd, m_patternId);
    448487        else
    449             fail(ASCIILiteral("The pattern cannot match anything."));
    450     }
    451 
    452     const String& errorMessage() const
    453     {
    454         return m_errorMessage;
     488            fail(URLFilterParser::CannotMatchAnything);
     489    }
     490
     491    URLFilterParser::ParseStatus parseStatus() const
     492    {
     493        return m_parseStatus;
    455494    }
    456495
     
    461500
    462501        if (!isASCII(character)) {
    463             fail(ASCIILiteral("Only ASCII characters are supported in pattern."));
     502            fail(URLFilterParser::NonASCII);
    464503            return;
    465504        }
     
    483522            m_floatingTerm = Term(Term::UniversalTransition);
    484523        else
    485             fail(ASCIILiteral("Character class is not supported."));
     524            fail(URLFilterParser::UnsupportedCharacterClass);
    486525    }
    487526
     
    492531
    493532        if (!m_floatingTerm.isValid())
    494             fail(ASCIILiteral("Quantifier without corresponding term to quantify."));
     533            fail(URLFilterParser::MisplacedQuantifier);
    495534
    496535        if (!minimum && maximum == 1)
     
    501540            m_floatingTerm.quantify(AtomQuantifier::OneOrMore);
    502541        else
    503             fail(ASCIILiteral("Arbitrary atom repetitions are not supported."));
     542            fail(URLFilterParser::InvalidQuantifier);
    504543    }
    505544
    506545    void atomBackReference(unsigned)
    507546    {
    508         fail(ASCIILiteral("Patterns cannot contain backreferences."));
     547        fail(URLFilterParser::BackReference);
    509548    }
    510549
     
    515554
    516555        if (m_subtreeStart != m_subtreeEnd || m_floatingTerm.isValid() || !m_openGroups.isEmpty())
    517             fail(ASCIILiteral("Start of line assertion can only appear as the first term in a filter."));
     556            fail(URLFilterParser::MisplacedStartOfLine);
    518557    }
    519558
     
    531570    void assertionWordBoundary(bool)
    532571    {
    533         fail(ASCIILiteral("Word boundaries assertions are not supported yet."));
     572        fail(URLFilterParser::WordBoundary);
    534573    }
    535574
     
    550589            return;
    551590
    552         if (!isASCII(character)) {
    553             fail(ASCIILiteral("Non ASCII Character in a character set."));
    554             return;
    555         }
     591        ASSERT(isASCII(character));
    556592
    557593        m_floatingTerm.addCharacter(character, m_patternIsCaseSensitive);
     
    563599            return;
    564600
    565         if (!a || !b || !isASCII(a) || !isASCII(b)) {
    566             fail(ASCIILiteral("Non ASCII Character in a character range of a character set."));
    567             return;
    568         }
     601        ASSERT(a);
     602        ASSERT(b);
     603        ASSERT(isASCII(a));
     604        ASSERT(isASCII(b));
    569605
    570606        for (unsigned i = a; i <= b; ++i)
     
    579615    void atomCharacterClassBuiltIn(JSC::Yarr::BuiltInCharacterClassID, bool)
    580616    {
    581         fail(ASCIILiteral("Builtins character class atoms are not supported yet."));
     617        fail(URLFilterParser::AtomCharacter);
    582618    }
    583619
     
    594630    void atomParentheticalAssertionBegin(bool = false)
    595631    {
    596         fail(ASCIILiteral("Groups are not supported yet."));
     632        fail(URLFilterParser::Group);
    597633    }
    598634
     
    610646    void disjunction()
    611647    {
    612         fail(ASCIILiteral("Disjunctions are not supported yet."));
     648        fail(URLFilterParser::Disjunction);
    613649    }
    614650
     
    616652    bool hasError() const
    617653    {
    618         return !m_errorMessage.isNull();
    619     }
    620 
    621     void fail(const String& errorMessage)
     654        return m_parseStatus != URLFilterParser::Ok;
     655    }
     656
     657    void fail(URLFilterParser::ParseStatus reason)
    622658    {
    623659        if (hasError())
     
    627663            m_newPrefixSubtreeRoot->nextPattern.remove(m_newPrefixStaringPoint);
    628664
    629         m_errorMessage = errorMessage;
     665        m_parseStatus = reason;
    630666    }
    631667
     
    635671            return;
    636672
    637         ASSERT(m_lastPrefixTreeEntry);
    638 
    639673        if (m_hasProcessedEndOfLineAssertion) {
    640             fail(ASCIILiteral("The end of line assertion must be the last term in an expression."));
     674            fail(URLFilterParser::MisplacedEndOfLine);
    641675            m_floatingTerm = Term();
    642676            return;
     
    652686        }
    653687
    654         auto nextEntry = m_lastPrefixTreeEntry->nextPattern.find(m_floatingTerm);
    655         if (nextEntry != m_lastPrefixTreeEntry->nextPattern.end()) {
    656             m_lastPrefixTreeEntry = nextEntry->value.get();
    657             m_nfa.addRuleId(m_lastPrefixTreeEntry->nfaNode, m_patternId);
    658         } else {
    659             std::unique_ptr<PrefixTreeEntry> nextPrefixTreeEntry = std::make_unique<PrefixTreeEntry>();
    660 
    661             unsigned newEnd = m_floatingTerm.generateGraph(m_nfa, m_patternId, m_lastPrefixTreeEntry->nfaNode);
    662             nextPrefixTreeEntry->nfaNode = newEnd;
    663 
    664             auto addResult = m_lastPrefixTreeEntry->nextPattern.set(m_floatingTerm, WTF::move(nextPrefixTreeEntry));
    665             ASSERT(addResult.isNewEntry);
    666 
    667             if (!m_newPrefixSubtreeRoot) {
    668                 m_newPrefixSubtreeRoot = m_lastPrefixTreeEntry;
    669                 m_newPrefixStaringPoint = m_floatingTerm;
    670             }
    671 
    672             m_lastPrefixTreeEntry = addResult.iterator->value.get();
    673         }
    674         m_subtreeEnd = m_lastPrefixTreeEntry->nfaNode;
    675 
     688        m_sunkTerms.append(m_floatingTerm);
    676689        m_floatingTerm = Term();
    677         ASSERT(m_lastPrefixTreeEntry);
    678690    }
    679691
     
    687699    PrefixTreeEntry* m_lastPrefixTreeEntry;
    688700    Deque<Term> m_openGroups;
     701    Vector<Term> m_sunkTerms;
    689702    Term m_floatingTerm;
    690703    bool m_hasProcessedEndOfLineAssertion { false };
     
    693706    Term m_newPrefixStaringPoint;
    694707
    695     String m_errorMessage;
     708    URLFilterParser::ParseStatus m_parseStatus;
    696709};
    697710
     
    707720}
    708721
    709 String URLFilterParser::addPattern(const String& pattern, bool patternIsCaseSensitive, uint64_t patternId)
     722URLFilterParser::ParseStatus URLFilterParser::addPattern(const String& pattern, bool patternIsCaseSensitive, uint64_t patternId)
    710723{
    711724    if (!pattern.containsOnlyASCII())
    712         return ASCIILiteral("URLFilterParser only supports ASCII patterns.");
     725        return NonASCII;
    713726    ASSERT(!pattern.isEmpty());
    714727
    715728    if (pattern.isEmpty())
    716         return ASCIILiteral("Empty pattern.");
     729        return EmptyPattern;
    717730
    718731    unsigned oldSize = m_nfa.graphSize();
    719732
    720     String error;
    721 
     733    ParseStatus status = Ok;
    722734    GraphBuilder graphBuilder(m_nfa, *m_prefixTreeRoot, patternIsCaseSensitive, patternId);
    723     error = String(JSC::Yarr::parse(graphBuilder, pattern, 0));
     735    String error = String(JSC::Yarr::parse(graphBuilder, pattern, 0));
    724736    if (error.isNull())
    725737        graphBuilder.finalize();
    726 
    727     if (error.isNull())
    728         error = graphBuilder.errorMessage();
    729 
    730     if (!error.isNull())
     738    else
     739        status = YarrError;
     740   
     741    if (status == Ok)
     742        status = graphBuilder.parseStatus();
     743
     744    if (status != Ok)
    731745        m_nfa.restoreToGraphSize(oldSize);
    732746
    733     return error;
     747    return status;
    734748}
    735749
     750String URLFilterParser::statusString(ParseStatus status)
     751{
     752    switch (status) {
     753    case Ok:
     754        return "Ok";
     755    case MatchesEverything:
     756        return "Matches everything.";
     757    case UnclosedGroups:
     758        return "The expression has unclosed groups.";
     759    case CannotMatchAnything:
     760        return "The pattern cannot match anything.";
     761    case NonASCII:
     762        return "Only ASCII characters are supported in pattern.";
     763    case UnsupportedCharacterClass:
     764        return "Character class is not supported.";
     765    case MisplacedQuantifier:
     766        return "Quantifier without corresponding term to quantify.";
     767    case BackReference:
     768        return "Patterns cannot contain backreferences.";
     769    case MisplacedStartOfLine:
     770        return "Start of line assertion can only appear as the first term in a filter.";
     771    case WordBoundary:
     772        return "Word boundaries assertions are not supported yet.";
     773    case AtomCharacter:
     774        return "Builtins character class atoms are not supported yet.";
     775    case Group:
     776        return "Groups are not supported yet.";
     777    case Disjunction:
     778        return "Disjunctions are not supported yet.";
     779    case MisplacedEndOfLine:
     780        return "The end of line assertion must be the last term in an expression.";
     781    case EmptyPattern:
     782        return "Empty pattern.";
     783    case YarrError:
     784        return "Internal error in YARR.";
     785    case InvalidQuantifier:
     786        return "Arbitrary atom repetitions are not supported.";
     787    }
     788}
     789   
    736790} // namespace ContentExtensions
    737791} // namespace WebCore
  • trunk/Source/WebCore/contentextensions/URLFilterParser.h

    r181282 r181726  
    4040struct PrefixTreeEntry;
    4141
    42 class URLFilterParser {
     42class WEBCORE_EXPORT URLFilterParser {
    4343public:
     44    enum ParseStatus {
     45        Ok,
     46        MatchesEverything,
     47        UnclosedGroups,
     48        CannotMatchAnything,
     49        NonASCII,
     50        UnsupportedCharacterClass,
     51        MisplacedQuantifier,
     52        BackReference,
     53        MisplacedStartOfLine,
     54        WordBoundary,
     55        AtomCharacter,
     56        Group,
     57        Disjunction,
     58        MisplacedEndOfLine,
     59        EmptyPattern,
     60        YarrError,
     61        InvalidQuantifier,
     62    };
     63    static String statusString(ParseStatus);
    4464    explicit URLFilterParser(NFA&);
    4565    ~URLFilterParser();
    46     String addPattern(const String& pattern, bool patternIsCaseSensitive, uint64_t patternId);
     66    ParseStatus addPattern(const String& pattern, bool patternIsCaseSensitive, uint64_t patternId);
    4767
    4868private:
  • trunk/Tools/ChangeLog

    r181717 r181726  
     12015-03-18  Alex Christensen  <achristensen@webkit.org>
     2
     3        [ContentExtensions] Prepare for compiling stylesheets of selectors to be used on every page.
     4        https://bugs.webkit.org/show_bug.cgi?id=142799
     5
     6        Reviewed by Brady Eidson.
     7
     8        * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
     9        (TestWebKitAPI::testPattern):
     10        (TestWebKitAPI::TEST_F):
     11        Start testing regex failures.
     12
    1132015-03-18  Dhi Aurrahman  <diorahman@rockybars.com>
    214
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp

    r181663 r181726  
    3030#include <WebCore/ContentExtensionCompiler.h>
    3131#include <WebCore/ContentExtensionsBackend.h>
     32#include <WebCore/NFA.h>
    3233#include <WebCore/ResourceLoadInfo.h>
    3334#include <WebCore/URL.h>
     35#include <WebCore/URLFilterParser.h>
    3436#include <wtf/MainThread.h>
    3537#include <wtf/RunLoop.h>
     38#include <wtf/text/CString.h>
    3639
    3740namespace WebCore {
     
    336339}
    337340
     341static void testPatternStatus(const char* pattern, ContentExtensions::URLFilterParser::ParseStatus status)
     342{
     343    ContentExtensions::NFA nfa;
     344    ContentExtensions::URLFilterParser parser(nfa);
     345    EXPECT_EQ(status, parser.addPattern(ASCIILiteral(pattern), false, 0));
     346}
     347   
     348TEST_F(ContentExtensionTest, ParsingFailures)
     349{
     350    testPatternStatus("a*b?.*.?[a-z]?[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
     351    testPatternStatus("a*b?.*.?[a-z]?[a-z]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
     352    testPatternStatus("a*b?.*.?[a-z]?[a-z]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
     353    // FIXME: Add regexes that cause each parse status.
     354}
     355
    338356} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.