Fix the !ENABLE(WEBGL) build after r180609
[WebKit-https.git] / Source / WebCore / contentextensions / ContentExtensionParser.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 "ContentExtensionParser.h"
28
29 #if ENABLE(CONTENT_EXTENSIONS)
30
31 #include "ContentExtensionRule.h"
32 #include "ContentExtensionsBackend.h"
33 #include "ContentExtensionsDebugging.h"
34 #include <JavaScriptCore/IdentifierInlines.h>
35 #include <JavaScriptCore/JSCJSValueInlines.h>
36 #include <JavaScriptCore/JSGlobalObject.h>
37 #include <JavaScriptCore/JSONObject.h>
38 #include <JavaScriptCore/StructureInlines.h>
39 #include <JavaScriptCore/VM.h>
40 #include <wtf/CurrentTime.h>
41 #include <wtf/text/WTFString.h>
42
43 using namespace JSC;
44
45 namespace WebCore {
46
47 namespace ContentExtensions {
48
49 static bool loadTrigger(ExecState& exec, JSObject& ruleObject, Trigger& trigger)
50 {
51     JSValue triggerObject = ruleObject.get(&exec, Identifier(&exec, "trigger"));
52     if (!triggerObject || exec.hadException() || !triggerObject.isObject()) {
53         WTFLogAlways("Invalid trigger object.");
54         return false;
55     }
56
57     JSValue urlFilterObject = triggerObject.get(&exec, Identifier(&exec, "url-filter"));
58     if (!urlFilterObject || exec.hadException() || !urlFilterObject.isString()) {
59         WTFLogAlways("Invalid url-filter object.");
60         return false;
61     }
62
63     String urlFilter = urlFilterObject.toWTFString(&exec);
64     if (urlFilter.isEmpty()) {
65         WTFLogAlways("Invalid url-filter object. The url is empty.");
66         return false;
67     }
68     trigger.urlFilter = urlFilter;
69
70     JSValue urlFilterCaseObject = triggerObject.get(&exec, Identifier(&exec, "url-filter-is-case-sensitive"));
71     if (urlFilterCaseObject && !exec.hadException() && urlFilterCaseObject.isBoolean())
72         trigger.urlFilterIsCaseSensitive = urlFilterCaseObject.toBoolean(&exec);
73
74     return true;
75 }
76
77 static bool loadAction(ExecState& exec, JSObject& ruleObject, Action& action)
78 {
79     JSValue actionObject = ruleObject.get(&exec, Identifier(&exec, "action"));
80     if (!actionObject || exec.hadException() || !actionObject.isObject()) {
81         WTFLogAlways("Invalid action object.");
82         return false;
83     }
84
85     JSValue typeObject = actionObject.get(&exec, Identifier(&exec, "type"));
86     if (!typeObject || exec.hadException() || !typeObject.isString()) {
87         WTFLogAlways("Invalid url-filter object.");
88         return false;
89     }
90
91     String actionType = typeObject.toWTFString(&exec);
92
93     if (actionType == "block")
94         action = ActionType::BlockLoad;
95     else if (actionType == "ignore-previous-rules")
96         action = ActionType::IgnorePreviousRules;
97     else if (actionType == "block-cookies")
98         action = ActionType::BlockCookies;
99     else if (actionType == "css-display-none") {
100         JSValue selector = actionObject.get(&exec, Identifier(&exec, "selector"));
101         if (!selector || exec.hadException() || !selector.isString()) {
102             WTFLogAlways("css-display-none action type requires a selector");
103             return false;
104         }
105         action = Action(ActionType::CSSDisplayNone, selector.toWTFString(&exec));
106     } else {
107         WTFLogAlways("Unrecognized action: \"%s\"", actionType.utf8().data());
108         return false;
109     }
110
111     return true;
112 }
113
114 static void loadRule(ExecState& exec, JSObject& ruleObject, Vector<ContentExtensionRule>& ruleList)
115 {
116     Trigger trigger;
117     if (!loadTrigger(exec, ruleObject, trigger))
118         return;
119
120     Action action;
121     if (!loadAction(exec, ruleObject, action))
122         return;
123
124     ruleList.append(ContentExtensionRule(trigger, action));
125 }
126
127 static Vector<ContentExtensionRule> loadEncodedRules(ExecState& exec, const String& rules)
128 {
129     JSValue decodedRules = JSONParse(&exec, rules);
130
131     if (exec.hadException() || !decodedRules) {
132         WTFLogAlways("Failed to parse the JSON string.");
133         return Vector<ContentExtensionRule>();
134     }
135
136     if (decodedRules.isObject()) {
137         JSObject* topLevelObject = decodedRules.toObject(&exec);
138         if (!topLevelObject || exec.hadException()) {
139             WTFLogAlways("Invalid input, the top level structure is not an object.");
140             return Vector<ContentExtensionRule>();
141         }
142
143         if (!isJSArray(topLevelObject)) {
144             WTFLogAlways("Invalid input, the top level object is not an array.");
145             return Vector<ContentExtensionRule>();
146         }
147
148         Vector<ContentExtensionRule> ruleList;
149         JSArray* topLevelArray = jsCast<JSArray*>(topLevelObject);
150
151         unsigned length = topLevelArray->length();
152         for (unsigned i = 0; i < length; ++i) {
153             JSValue value = topLevelArray->getIndex(&exec, i);
154             if (exec.hadException() || !value) {
155                 WTFLogAlways("Invalid object in the array.");
156                 continue;
157             }
158
159             JSObject* ruleObject = value.toObject(&exec);
160             if (!ruleObject || exec.hadException()) {
161                 WTFLogAlways("Invalid rule");
162                 continue;
163             }
164             loadRule(exec, *ruleObject, ruleList);
165         }
166         return ruleList;
167     }
168     return Vector<ContentExtensionRule>();
169 }
170
171 Vector<ContentExtensionRule> parseRuleList(const String& rules)
172 {
173 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
174     double loadExtensionStartTime = monotonicallyIncreasingTime();
175 #endif
176     RefPtr<VM> vm = VM::create();
177
178     JSLockHolder locker(vm.get());
179     JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
180
181     ExecState* exec = globalObject->globalExec();
182     Vector<ContentExtensionRule> ruleList = loadEncodedRules(*exec, rules);
183
184     vm.clear();
185
186     if (ruleList.isEmpty())
187         WTFLogAlways("Empty extension.");
188
189 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
190     double loadExtensionEndTime = monotonicallyIncreasingTime();
191     dataLogF("Time spent loading extension %s: %f\n", identifier.utf8().data(), (loadExtensionEndTime - loadExtensionStartTime));
192 #endif
193
194     return ruleList;
195 }
196
197 } // namespace ContentExtensions
198 } // namespace WebCore
199
200 #endif // ENABLE(CONTENT_EXTENSIONS)