1 | /* |
2 | * Copyright (C) 2014, 2018-2019 Igalia S.L. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Library General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Library General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Library General Public License |
15 | * along with this library; see the file COPYING.LIB. If not, write to |
16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | * Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "config.h" |
21 | #include "WebKitUserContent.h" |
22 | |
23 | #include "WebKitUserContentPrivate.h" |
24 | #include <wtf/HashMap.h> |
25 | #include <wtf/NeverDestroyed.h> |
26 | #include <wtf/text/CString.h> |
27 | |
28 | using namespace WebCore; |
29 | |
30 | /** |
31 | * SECTION:WebKitUserContent |
32 | * @short_description: Defines user content types which affect web pages. |
33 | * @title: User content |
34 | * |
35 | * See also: #WebKitUserContentManager |
36 | * |
37 | * Since: 2.6 |
38 | */ |
39 | |
40 | |
41 | API::UserContentWorld& webkitUserContentWorld(const char* worldName) |
42 | { |
43 | static NeverDestroyed<HashMap<CString, RefPtr<API::UserContentWorld>>> map; |
44 | return *map.get().ensure(worldName, [worldName = String::fromUTF8(worldName)] { return API::UserContentWorld::worldWithName(worldName); }).iterator->value; |
45 | } |
46 | |
47 | static inline UserContentInjectedFrames toUserContentInjectedFrames(WebKitUserContentInjectedFrames injectedFrames) |
48 | { |
49 | switch (injectedFrames) { |
50 | case WEBKIT_USER_CONTENT_INJECT_TOP_FRAME: |
51 | return InjectInTopFrameOnly; |
52 | case WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES: |
53 | return InjectInAllFrames; |
54 | default: |
55 | ASSERT_NOT_REACHED(); |
56 | return InjectInAllFrames; |
57 | } |
58 | } |
59 | |
60 | static inline UserStyleLevel toUserStyleLevel(WebKitUserStyleLevel styleLevel) |
61 | { |
62 | switch (styleLevel) { |
63 | case WEBKIT_USER_STYLE_LEVEL_USER: |
64 | return UserStyleUserLevel; |
65 | case WEBKIT_USER_STYLE_LEVEL_AUTHOR: |
66 | return UserStyleAuthorLevel; |
67 | default: |
68 | ASSERT_NOT_REACHED(); |
69 | return UserStyleAuthorLevel; |
70 | } |
71 | } |
72 | |
73 | static inline UserScriptInjectionTime toUserScriptInjectionTime(WebKitUserScriptInjectionTime injectionTime) |
74 | { |
75 | switch (injectionTime) { |
76 | case WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START: |
77 | return InjectAtDocumentStart; |
78 | case WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END: |
79 | return InjectAtDocumentEnd; |
80 | default: |
81 | ASSERT_NOT_REACHED(); |
82 | return InjectAtDocumentStart; |
83 | } |
84 | } |
85 | |
86 | static inline Vector<String> toStringVector(const char* const* strv) |
87 | { |
88 | if (!strv) |
89 | return Vector<String>(); |
90 | |
91 | Vector<String> result; |
92 | for (auto str = strv; *str; ++str) |
93 | result.append(String::fromUTF8(*str)); |
94 | return result; |
95 | } |
96 | |
97 | struct _WebKitUserStyleSheet { |
98 | _WebKitUserStyleSheet(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserStyleLevel level, const char* const* whitelist, const char* const* blacklist, API::UserContentWorld& world) |
99 | : userStyleSheet(adoptRef(new API::UserStyleSheet(UserStyleSheet { |
100 | String::fromUTF8(source), URL { }, |
101 | toStringVector(whitelist), toStringVector(blacklist), |
102 | toUserContentInjectedFrames(injectedFrames), |
103 | toUserStyleLevel(level) }, world))) |
104 | , referenceCount(1) |
105 | { |
106 | } |
107 | |
108 | RefPtr<API::UserStyleSheet> userStyleSheet; |
109 | int referenceCount; |
110 | }; |
111 | |
112 | G_DEFINE_BOXED_TYPE(WebKitUserStyleSheet, webkit_user_style_sheet, webkit_user_style_sheet_ref, webkit_user_style_sheet_unref) |
113 | |
114 | /** |
115 | * webkit_user_style_sheet_ref: |
116 | * @user_style_sheet: a #WebKitUserStyleSheet |
117 | * |
118 | * Atomically increments the reference count of @user_style_sheet by one. |
119 | * This function is MT-safe and may be called from any thread. |
120 | * |
121 | * Returns: The passed #WebKitUserStyleSheet |
122 | * |
123 | * Since: 2.6 |
124 | */ |
125 | WebKitUserStyleSheet* webkit_user_style_sheet_ref(WebKitUserStyleSheet* userStyleSheet) |
126 | { |
127 | g_atomic_int_inc(&userStyleSheet->referenceCount); |
128 | return userStyleSheet; |
129 | } |
130 | |
131 | /** |
132 | * webkit_user_style_sheet_unref: |
133 | * @user_style_sheet: a #WebKitUserStyleSheet |
134 | * |
135 | * Atomically decrements the reference count of @user_style_sheet by one. |
136 | * If the reference count drops to 0, all memory allocated by |
137 | * #WebKitUserStyleSheet is released. This function is MT-safe and may be |
138 | * called from any thread. |
139 | * |
140 | * Since: 2.6 |
141 | */ |
142 | void webkit_user_style_sheet_unref(WebKitUserStyleSheet* userStyleSheet) |
143 | { |
144 | if (g_atomic_int_dec_and_test(&userStyleSheet->referenceCount)) { |
145 | userStyleSheet->~WebKitUserStyleSheet(); |
146 | fastFree(userStyleSheet); |
147 | } |
148 | } |
149 | |
150 | /** |
151 | * webkit_user_style_sheet_new: |
152 | * @source: Source code of the user style sheet. |
153 | * @injected_frames: A #WebKitUserContentInjectedFrames value |
154 | * @level: A #WebKitUserStyleLevel |
155 | * @whitelist: (array zero-terminated=1) (allow-none): A whitelist of URI patterns or %NULL |
156 | * @blacklist: (array zero-terminated=1) (allow-none): A blacklist of URI patterns or %NULL |
157 | * |
158 | * Creates a new user style sheet. Style sheets can be applied to some URIs |
159 | * only by passing non-null values for @whitelist or @blacklist. Passing a |
160 | * %NULL whitelist implies that all URIs are on the whitelist. The style |
161 | * sheet is applied if an URI matches the whitelist and not the blacklist. |
162 | * URI patterns must be of the form `[protocol]://[host]/[path]`, where the |
163 | * *host* and *path* components can contain the wildcard character (`*`) to |
164 | * represent zero or more other characters. |
165 | * |
166 | * Returns: A new #WebKitUserStyleSheet |
167 | * |
168 | * Since: 2.6 |
169 | */ |
170 | WebKitUserStyleSheet* webkit_user_style_sheet_new(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserStyleLevel level, const char* const* whitelist, const char* const* blacklist) |
171 | { |
172 | g_return_val_if_fail(source, nullptr); |
173 | WebKitUserStyleSheet* userStyleSheet = static_cast<WebKitUserStyleSheet*>(fastMalloc(sizeof(WebKitUserStyleSheet))); |
174 | new (userStyleSheet) WebKitUserStyleSheet(source, injectedFrames, level, whitelist, blacklist, API::UserContentWorld::normalWorld()); |
175 | return userStyleSheet; |
176 | } |
177 | |
178 | /** |
179 | * webkit_user_style_sheet_new_for_world: |
180 | * @source: Source code of the user style sheet. |
181 | * @injected_frames: A #WebKitUserContentInjectedFrames value |
182 | * @level: A #WebKitUserStyleLevel |
183 | * @world_name: the name of a #WebKitScriptWorld |
184 | * @whitelist: (array zero-terminated=1) (allow-none): A whitelist of URI patterns or %NULL |
185 | * @blacklist: (array zero-terminated=1) (allow-none): A blacklist of URI patterns or %NULL |
186 | * |
187 | * Creates a new user style sheet for script world with name @world_name. |
188 | * See webkit_user_style_sheet_new() for a full description. |
189 | * |
190 | * Returns: A new #WebKitUserStyleSheet |
191 | * |
192 | * Since: 2.22 |
193 | */ |
194 | WebKitUserStyleSheet* webkit_user_style_sheet_new_for_world(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserStyleLevel level, const char* worldName, const char* const* whitelist, const char* const* blacklist) |
195 | { |
196 | g_return_val_if_fail(source, nullptr); |
197 | g_return_val_if_fail(worldName, nullptr); |
198 | |
199 | WebKitUserStyleSheet* userStyleSheet = static_cast<WebKitUserStyleSheet*>(fastMalloc(sizeof(WebKitUserStyleSheet))); |
200 | new (userStyleSheet) WebKitUserStyleSheet(source, injectedFrames, level, whitelist, blacklist, webkitUserContentWorld(worldName)); |
201 | return userStyleSheet; |
202 | } |
203 | |
204 | API::UserStyleSheet& webkitUserStyleSheetGetUserStyleSheet(WebKitUserStyleSheet* userStyleSheet) |
205 | { |
206 | return *userStyleSheet->userStyleSheet; |
207 | } |
208 | |
209 | struct _WebKitUserScript { |
210 | _WebKitUserScript(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserScriptInjectionTime injectionTime, const gchar* const* whitelist, const gchar* const* blacklist, API::UserContentWorld& world) |
211 | : userScript(adoptRef(new API::UserScript(UserScript { |
212 | String::fromUTF8(source), URL { }, |
213 | toStringVector(whitelist), toStringVector(blacklist), |
214 | toUserScriptInjectionTime(injectionTime), |
215 | toUserContentInjectedFrames(injectedFrames) }, world))) |
216 | , referenceCount(1) |
217 | { |
218 | } |
219 | |
220 | RefPtr<API::UserScript> userScript; |
221 | int referenceCount; |
222 | }; |
223 | |
224 | G_DEFINE_BOXED_TYPE(WebKitUserScript, webkit_user_script, webkit_user_script_ref, webkit_user_script_unref) |
225 | |
226 | /** |
227 | * webkit_user_script_ref: |
228 | * @user_script: a #WebKitUserScript |
229 | * |
230 | * Atomically increments the reference count of @user_script by one. |
231 | * This function is MT-safe and may be called from any thread. |
232 | * |
233 | * Returns: The passed #WebKitUserScript |
234 | * |
235 | * Since: 2.6 |
236 | */ |
237 | WebKitUserScript* webkit_user_script_ref(WebKitUserScript* userScript) |
238 | { |
239 | g_atomic_int_inc(&userScript->referenceCount); |
240 | return userScript; |
241 | } |
242 | |
243 | /** |
244 | * webkit_user_script_unref: |
245 | * @user_script: a #WebKitUserScript |
246 | * |
247 | * Atomically decrements the reference count of @user_script by one. |
248 | * If the reference count drops to 0, all memory allocated by |
249 | * #WebKitUserScript is released. This function is MT-safe and may be called |
250 | * from any thread. |
251 | * |
252 | * Since: 2.6 |
253 | */ |
254 | void webkit_user_script_unref(WebKitUserScript* userScript) |
255 | { |
256 | if (g_atomic_int_dec_and_test(&userScript->referenceCount)) { |
257 | userScript->~WebKitUserScript(); |
258 | fastFree(userScript); |
259 | } |
260 | } |
261 | |
262 | /** |
263 | * webkit_user_script_new: |
264 | * @source: Source code of the user script. |
265 | * @injected_frames: A #WebKitUserContentInjectedFrames value |
266 | * @injection_time: A #WebKitUserScriptInjectionTime value |
267 | * @whitelist: (array zero-terminated=1) (allow-none): A whitelist of URI patterns or %NULL |
268 | * @blacklist: (array zero-terminated=1) (allow-none): A blacklist of URI patterns or %NULL |
269 | * |
270 | * Creates a new user script. Scripts can be applied to some URIs |
271 | * only by passing non-null values for @whitelist or @blacklist. Passing a |
272 | * %NULL whitelist implies that all URIs are on the whitelist. The script |
273 | * is applied if an URI matches the whitelist and not the blacklist. |
274 | * URI patterns must be of the form `[protocol]://[host]/[path]`, where the |
275 | * *host* and *path* components can contain the wildcard character (`*`) to |
276 | * represent zero or more other characters. |
277 | * |
278 | * Returns: A new #WebKitUserScript |
279 | * |
280 | * Since: 2.6 |
281 | */ |
282 | WebKitUserScript* webkit_user_script_new(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserScriptInjectionTime injectionTime, const gchar* const* whitelist, const gchar* const* blacklist) |
283 | { |
284 | g_return_val_if_fail(source, nullptr); |
285 | WebKitUserScript* userScript = static_cast<WebKitUserScript*>(fastMalloc(sizeof(WebKitUserScript))); |
286 | new (userScript) WebKitUserScript(source, injectedFrames, injectionTime, whitelist, blacklist, API::UserContentWorld::normalWorld()); |
287 | return userScript; |
288 | } |
289 | |
290 | /** |
291 | * webkit_user_script_new_for_world: |
292 | * @source: Source code of the user script. |
293 | * @injected_frames: A #WebKitUserContentInjectedFrames value |
294 | * @injection_time: A #WebKitUserScriptInjectionTime value |
295 | * @world_name: the name of a #WebKitScriptWorld |
296 | * @whitelist: (array zero-terminated=1) (allow-none): A whitelist of URI patterns or %NULL |
297 | * @blacklist: (array zero-terminated=1) (allow-none): A blacklist of URI patterns or %NULL |
298 | * |
299 | * Creates a new user script for script world with name @world_name. |
300 | * See webkit_user_script_new() for a full description. |
301 | * |
302 | * Returns: A new #WebKitUserScript |
303 | * |
304 | * Since: 2.22 |
305 | */ |
306 | WebKitUserScript* webkit_user_script_new_for_world(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserScriptInjectionTime injectionTime, const char* worldName, const gchar* const* whitelist, const gchar* const* blacklist) |
307 | { |
308 | g_return_val_if_fail(source, nullptr); |
309 | g_return_val_if_fail(worldName, nullptr); |
310 | |
311 | WebKitUserScript* userScript = static_cast<WebKitUserScript*>(fastMalloc(sizeof(WebKitUserScript))); |
312 | new (userScript) WebKitUserScript(source, injectedFrames, injectionTime, whitelist, blacklist, webkitUserContentWorld(worldName)); |
313 | return userScript; |
314 | } |
315 | |
316 | API::UserScript& webkitUserScriptGetUserScript(WebKitUserScript* userScript) |
317 | { |
318 | return *userScript->userScript; |
319 | } |
320 | |
321 | |
322 | struct _WebKitUserContentFilter { |
323 | _WebKitUserContentFilter(RefPtr<API::ContentRuleList>&& contentRuleList) |
324 | : identifier(contentRuleList->name().utf8()) |
325 | , contentRuleList(WTFMove(contentRuleList)) |
326 | , referenceCount(1) |
327 | { |
328 | } |
329 | |
330 | CString identifier; |
331 | RefPtr<API::ContentRuleList> contentRuleList; |
332 | int referenceCount; |
333 | }; |
334 | |
335 | G_DEFINE_BOXED_TYPE(WebKitUserContentFilter, webkit_user_content_filter, webkit_user_content_filter_ref, webkit_user_content_filter_unref) |
336 | |
337 | /** |
338 | * webkit_user_content_filter_ref: |
339 | * @user_content_filter: A #WebKitUserContentFilter |
340 | * |
341 | * Atomically increments the reference count of @user_content_filter by one. |
342 | * This function is MT-safe and may be called from any thread. |
343 | * |
344 | * Since: 2.24 |
345 | */ |
346 | WebKitUserContentFilter* webkit_user_content_filter_ref(WebKitUserContentFilter* userContentFilter) |
347 | { |
348 | g_return_val_if_fail(userContentFilter, nullptr); |
349 | g_atomic_int_inc(&userContentFilter->referenceCount); |
350 | return userContentFilter; |
351 | } |
352 | |
353 | /** |
354 | * webkit_user_content_filter_unref: |
355 | * @user_content_filter: A #WebKitUserContentFilter |
356 | * |
357 | * Atomically decrements the reference count of @user_content_filter by one. |
358 | * If the reference count drops to 0, all the memory allocated by the |
359 | * #WebKitUserContentFilter is released. This function is MT-safe and may |
360 | * be called from any thread. |
361 | * |
362 | * Since: 2.24 |
363 | */ |
364 | void webkit_user_content_filter_unref(WebKitUserContentFilter* userContentFilter) |
365 | { |
366 | g_return_if_fail(userContentFilter); |
367 | if (g_atomic_int_dec_and_test(&userContentFilter->referenceCount)) { |
368 | userContentFilter->~WebKitUserContentFilter(); |
369 | fastFree(userContentFilter); |
370 | } |
371 | } |
372 | |
373 | /** |
374 | * webkit_user_content_filter_get_identifier: |
375 | * @user_content_filter: A #WebKitUserContentFilter |
376 | * |
377 | * Obtain the identifier previously used to save the @user_content_filter in the |
378 | * #WebKitUserContentFilterStore. |
379 | * |
380 | * Returns: (transfer none): the identifier for the filter |
381 | * |
382 | * Since: 2.24 |
383 | */ |
384 | const char* webkit_user_content_filter_get_identifier(WebKitUserContentFilter* userContentFilter) |
385 | { |
386 | g_return_val_if_fail(userContentFilter, nullptr); |
387 | return userContentFilter->identifier.data(); |
388 | } |
389 | |
390 | WebKitUserContentFilter* webkitUserContentFilterCreate(RefPtr<API::ContentRuleList>&& contentRuleList) |
391 | { |
392 | WebKitUserContentFilter* userContentFilter = static_cast<WebKitUserContentFilter*>(fastMalloc(sizeof(WebKitUserContentFilter))); |
393 | new (userContentFilter) WebKitUserContentFilter(WTFMove(contentRuleList)); |
394 | return userContentFilter; |
395 | } |
396 | |
397 | API::ContentRuleList& webkitUserContentFilterGetContentRuleList(WebKitUserContentFilter* userContentFilter) |
398 | { |
399 | ASSERT(userContentFilter); |
400 | return *userContentFilter->contentRuleList; |
401 | } |
402 | |