fe78fc34a51a0b38f123a9a77bd5ffe40bca5122
[WebKit-https.git] / Source / WebCore / contentextensions / ContentExtensionsBackend.cpp
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ContentExtensionsBackend.h"
28
29 #if ENABLE(CONTENT_EXTENSIONS)
30
31 #include "ContentExtensionsDebugging.h"
32 #include "DFABytecodeCompiler.h"
33 #include "DFABytecodeInterpreter.h"
34 #include "NFA.h"
35 #include "NFAToDFA.h"
36 #include "URL.h"
37 #include "URLFilterParser.h"
38 #include <wtf/CurrentTime.h>
39 #include <wtf/DataLog.h>
40 #include <wtf/NeverDestroyed.h>
41 #include <wtf/text/CString.h>
42
43 namespace WebCore {
44
45 namespace ContentExtensions {
46
47 void ContentExtensionsBackend::setRuleList(const String& identifier, const Vector<ContentExtensionRule>& ruleList)
48 {
49     ASSERT(!identifier.isEmpty());
50     if (identifier.isEmpty())
51         return;
52
53     if (ruleList.isEmpty()) {
54         removeRuleList(identifier);
55         return;
56     }
57
58 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
59     double nfaBuildTimeStart = monotonicallyIncreasingTime();
60 #endif
61
62     NFA nfa;
63     URLFilterParser urlFilterParser(nfa);
64     for (unsigned ruleIndex = 0; ruleIndex < ruleList.size(); ++ruleIndex) {
65         const ContentExtensionRule& contentExtensionRule = ruleList[ruleIndex];
66         const ContentExtensionRule::Trigger& trigger = contentExtensionRule.trigger();
67         ASSERT(trigger.urlFilter.length());
68
69         String error = urlFilterParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, ruleIndex);
70
71         if (!error.isNull()) {
72             dataLogF("Error while parsing %s: %s\n", trigger.urlFilter.utf8().data(), error.utf8().data());
73             continue;
74         }
75     }
76
77 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
78     double nfaBuildTimeEnd = monotonicallyIncreasingTime();
79     dataLogF("    Time spent building the NFA: %f\n", (nfaBuildTimeEnd - nfaBuildTimeStart));
80 #endif
81
82 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
83     nfa.debugPrintDot();
84 #endif
85
86 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
87     double dfaBuildTimeStart = monotonicallyIncreasingTime();
88 #endif
89
90     const DFA dfa = NFAToDFA::convert(nfa);
91
92 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
93     double dfaBuildTimeEnd = monotonicallyIncreasingTime();
94     dataLogF("    Time spent building the DFA: %f\n", (dfaBuildTimeEnd - dfaBuildTimeStart));
95 #endif
96
97     // FIXME: never add a DFA that only matches the empty set.
98
99 #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
100     dfa.debugPrintDot();
101 #endif
102
103     Vector<DFABytecode> bytecode;
104     DFABytecodeCompiler compiler(dfa, bytecode);
105     compiler.compile();
106     CompiledContentExtension compiledContentExtension = { bytecode, ruleList };
107     m_ruleLists.set(identifier, compiledContentExtension);
108 }
109
110 void ContentExtensionsBackend::removeRuleList(const String& identifier)
111 {
112     m_ruleLists.remove(identifier);
113 }
114
115 void ContentExtensionsBackend::removeAllRuleLists()
116 {
117     m_ruleLists.clear();
118 }
119
120 ContentFilterAction ContentExtensionsBackend::actionForURL(const URL& url)
121 {
122     const String& urlString = url.string();
123     ASSERT_WITH_MESSAGE(urlString.containsOnlyASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
124     const CString& urlCString = urlString.utf8();
125
126     for (auto& ruleListSlot : m_ruleLists) {
127         const CompiledContentExtension& compiledContentExtension = ruleListSlot.value;
128         DFABytecodeInterpreter interpreter(compiledContentExtension.bytecode);
129         DFABytecodeInterpreter::Actions triggeredActions = interpreter.interpret(urlCString);
130         // FIXME: We should eventually do something with each action rather than just returning a bool.
131         if (!triggeredActions.isEmpty()) {
132             Vector<uint64_t> sortedActions;
133             copyToVector(triggeredActions, sortedActions);
134             std::sort(sortedActions.begin(), sortedActions.end());
135             size_t lastAction = static_cast<size_t>(sortedActions.last());
136             ExtensionActionType type = compiledContentExtension.ruleList[lastAction].action().type;
137
138             if (type == ExtensionActionType::BlockLoad)
139                 return ContentFilterAction::Block;
140             if (type == ExtensionActionType::BlockCookies)
141                 return ContentFilterAction::BlockCookies;
142         }
143     }
144
145     return ContentFilterAction::Load;
146 }
147
148 } // namespace ContentExtensions
149
150 } // namespace WebCore
151
152 #endif // ENABLE(CONTENT_EXTENSIONS)