[GTK][WPE] Stop using legacy custom protocol implementation
[WebKit-https.git] / Source / WebKit / UIProcess / API / glib / WebKitWebContext.cpp
1 /*
2  * Copyright (C) 2011 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 "WebKitWebContext.h"
22
23 #include "APIAutomationClient.h"
24 #include "APIDownloadClient.h"
25 #include "APIInjectedBundleClient.h"
26 #include "APIPageConfiguration.h"
27 #include "APIProcessPoolConfiguration.h"
28 #include "APIString.h"
29 #include "LegacyGlobalSettings.h"
30 #include "TextChecker.h"
31 #include "TextCheckerState.h"
32 #include "WebAutomationSession.h"
33 #include "WebCertificateInfo.h"
34 #include "WebKitAutomationSessionPrivate.h"
35 #include "WebKitDownloadClient.h"
36 #include "WebKitDownloadPrivate.h"
37 #include "WebKitFaviconDatabasePrivate.h"
38 #include "WebKitGeolocationManagerPrivate.h"
39 #include "WebKitInjectedBundleClient.h"
40 #include "WebKitNetworkProxySettingsPrivate.h"
41 #include "WebKitNotificationProvider.h"
42 #include "WebKitPluginPrivate.h"
43 #include "WebKitPrivate.h"
44 #include "WebKitProtocolHandler.h"
45 #include "WebKitSecurityManagerPrivate.h"
46 #include "WebKitSecurityOriginPrivate.h"
47 #include "WebKitSettingsPrivate.h"
48 #include "WebKitURISchemeRequestPrivate.h"
49 #include "WebKitUserContentManagerPrivate.h"
50 #include "WebKitWebContextPrivate.h"
51 #include "WebKitWebViewPrivate.h"
52 #include "WebKitWebsiteDataManagerPrivate.h"
53 #include "WebNotificationManagerProxy.h"
54 #include "WebURLSchemeHandler.h"
55 #include "WebsiteDataType.h"
56 #include <JavaScriptCore/RemoteInspector.h>
57 #include <glib/gi18n-lib.h>
58 #include <libintl.h>
59 #include <memory>
60 #include <wtf/FileSystem.h>
61 #include <wtf/HashMap.h>
62 #include <wtf/Language.h>
63 #include <wtf/NeverDestroyed.h>
64 #include <wtf/RefCounted.h>
65 #include <wtf/RefPtr.h>
66 #include <wtf/glib/GRefPtr.h>
67 #include <wtf/glib/GUniquePtr.h>
68 #include <wtf/glib/WTFGType.h>
69 #include <wtf/text/CString.h>
70
71 #if PLATFORM(GTK)
72 #include "WebKitRemoteInspectorProtocolHandler.h"
73 #endif
74
75 using namespace WebKit;
76
77 /**
78  * SECTION: WebKitWebContext
79  * @Short_description: Manages aspects common to all #WebKitWebView<!-- -->s
80  * @Title: WebKitWebContext
81  *
82  * The #WebKitWebContext manages all aspects common to all
83  * #WebKitWebView<!-- -->s.
84  *
85  * You can define the #WebKitCacheModel and #WebKitProcessModel with
86  * webkit_web_context_set_cache_model() and
87  * webkit_web_context_set_process_model(), depending on the needs of
88  * your application. You can access the #WebKitSecurityManager to specify
89  * the behaviour of your application regarding security using
90  * webkit_web_context_get_security_manager().
91  *
92  * It is also possible to change your preferred language or enable
93  * spell checking, using webkit_web_context_set_preferred_languages(),
94  * webkit_web_context_set_spell_checking_languages() and
95  * webkit_web_context_set_spell_checking_enabled().
96  *
97  * You can use webkit_web_context_register_uri_scheme() to register
98  * custom URI schemes, and manage several other settings.
99  *
100  * TLS certificate validation failure is now treated as a transport
101  * error by default. To handle TLS failures differently, you can
102  * connect to #WebKitWebView::load-failed-with-tls-errors.
103  * Alternatively, you can use webkit_web_context_set_tls_errors_policy()
104  * to set the policy %WEBKIT_TLS_ERRORS_POLICY_IGNORE; however, this is
105  * not appropriate for Internet applications.
106  *
107  */
108
109 enum {
110     PROP_0,
111
112 #if PLATFORM(GTK)
113     PROP_LOCAL_STORAGE_DIRECTORY,
114 #endif
115     PROP_WEBSITE_DATA_MANAGER
116 };
117
118 enum {
119     DOWNLOAD_STARTED,
120     INITIALIZE_WEB_EXTENSIONS,
121     INITIALIZE_NOTIFICATION_PERMISSIONS,
122     AUTOMATION_STARTED,
123
124     LAST_SIGNAL
125 };
126
127 class WebKitURISchemeHandler final : public WebURLSchemeHandler {
128 public:
129     static Ref<WebKitURISchemeHandler> create(WebKitWebContext* context, WebKitURISchemeRequestCallback callback, void* userData, GDestroyNotify destroyNotify)
130     {
131         return adoptRef(*new WebKitURISchemeHandler(context, callback, userData, destroyNotify));
132     }
133
134     ~WebKitURISchemeHandler()
135     {
136         if (m_destroyNotify)
137             m_destroyNotify(m_userData);
138     }
139
140 private:
141     WebKitURISchemeHandler(WebKitWebContext* context, WebKitURISchemeRequestCallback callback, void* userData, GDestroyNotify destroyNotify)
142         : m_context(context)
143         , m_callback(callback)
144         , m_userData(userData)
145         , m_destroyNotify(destroyNotify)
146     {
147     }
148
149     void platformStartTask(WebPageProxy& page, WebURLSchemeTask& task) final
150     {
151         if (!m_callback)
152             return;
153
154         GRefPtr<WebKitURISchemeRequest> request = adoptGRef(webkitURISchemeRequestCreate(m_context, page, task));
155         auto addResult = m_requests.add(task.identifier(), WTFMove(request));
156         ASSERT(addResult.isNewEntry);
157         m_callback(addResult.iterator->value.get(), m_userData);
158     }
159
160     void platformStopTask(WebPageProxy&, WebURLSchemeTask& task) final
161     {
162         auto it = m_requests.find(task.identifier());
163         if (it == m_requests.end())
164             return;
165
166         webkitURISchemeRequestCancel(it->value.get());
167         m_requests.remove(it);
168     }
169
170     void platformTaskCompleted(WebURLSchemeTask& task) final
171     {
172         m_requests.remove(task.identifier());
173     }
174
175     WebKitWebContext* m_context { nullptr };
176     WebKitURISchemeRequestCallback m_callback { nullptr };
177     void* m_userData { nullptr };
178     GDestroyNotify m_destroyNotify { nullptr };
179     HashMap<uint64_t, GRefPtr<WebKitURISchemeRequest>> m_requests;
180 };
181
182 typedef HashMap<String, RefPtr<WebKitURISchemeHandler> > URISchemeHandlerMap;
183 typedef HashMap<uint64_t, GRefPtr<WebKitURISchemeRequest> > URISchemeRequestMap;
184
185 class WebKitAutomationClient;
186
187 struct _WebKitWebContextPrivate {
188     RefPtr<WebProcessPool> processPool;
189     bool clientsDetached;
190
191     GRefPtr<WebKitFaviconDatabase> faviconDatabase;
192     GRefPtr<WebKitSecurityManager> securityManager;
193     URISchemeHandlerMap uriSchemeHandlers;
194     GRefPtr<WebKitGeolocationManager> geolocationManager;
195     std::unique_ptr<WebKitNotificationProvider> notificationProvider;
196     GRefPtr<WebKitWebsiteDataManager> websiteDataManager;
197
198     CString faviconDatabaseDirectory;
199     WebKitTLSErrorsPolicy tlsErrorsPolicy;
200     WebKitProcessModel processModel;
201
202     HashMap<uint64_t, WebKitWebView*> webViews;
203
204     CString webExtensionsDirectory;
205     GRefPtr<GVariant> webExtensionsInitializationUserData;
206
207     CString localStorageDirectory;
208 #if ENABLE(REMOTE_INSPECTOR)
209 #if PLATFORM(GTK)
210     std::unique_ptr<RemoteInspectorProtocolHandler> remoteInspectorProtocolHandler;
211 #endif
212     std::unique_ptr<WebKitAutomationClient> automationClient;
213     GRefPtr<WebKitAutomationSession> automationSession;
214 #endif
215     std::unique_ptr<WebKitProtocolHandler> webkitProtocolHandler;
216 };
217
218 static guint signals[LAST_SIGNAL] = { 0, };
219
220 #if ENABLE(REMOTE_INSPECTOR)
221 class WebKitAutomationClient final : Inspector::RemoteInspector::Client {
222     WTF_MAKE_FAST_ALLOCATED;
223 public:
224     explicit WebKitAutomationClient(WebKitWebContext* context)
225         : m_webContext(context)
226     {
227         Inspector::RemoteInspector::singleton().setClient(this);
228     }
229
230     ~WebKitAutomationClient()
231     {
232         Inspector::RemoteInspector::singleton().setClient(nullptr);
233     }
234
235 private:
236     bool remoteAutomationAllowed() const override { return true; }
237
238     String browserName() const override
239     {
240         if (!m_webContext->priv->automationSession)
241             return { };
242
243         return webkitAutomationSessionGetBrowserName(m_webContext->priv->automationSession.get());
244     }
245
246     String browserVersion() const override
247     {
248         if (!m_webContext->priv->automationSession)
249             return { };
250
251         return webkitAutomationSessionGetBrowserVersion(m_webContext->priv->automationSession.get());
252     }
253
254     void requestAutomationSession(const String& sessionIdentifier, const Inspector::RemoteInspector::Client::SessionCapabilities& capabilities) override
255     {
256         ASSERT(!m_webContext->priv->automationSession);
257         m_webContext->priv->automationSession = adoptGRef(webkitAutomationSessionCreate(m_webContext, sessionIdentifier.utf8().data(), capabilities));
258         g_signal_emit(m_webContext, signals[AUTOMATION_STARTED], 0, m_webContext->priv->automationSession.get());
259         m_webContext->priv->processPool->setAutomationSession(&webkitAutomationSessionGetSession(m_webContext->priv->automationSession.get()));
260     }
261
262     WebKitWebContext* m_webContext;
263 };
264
265 void webkitWebContextWillCloseAutomationSession(WebKitWebContext* webContext)
266 {
267     webContext->priv->processPool->setAutomationSession(nullptr);
268     webContext->priv->automationSession = nullptr;
269 }
270 #endif // ENABLE(REMOTE_INSPECTOR)
271
272 WEBKIT_DEFINE_TYPE(WebKitWebContext, webkit_web_context, G_TYPE_OBJECT)
273
274 #if PLATFORM(GTK)
275 #define INJECTED_BUNDLE_FILENAME "libwebkit2gtkinjectedbundle.so"
276 #elif PLATFORM(WPE)
277 #define INJECTED_BUNDLE_FILENAME "libWPEInjectedBundle.so"
278 #endif
279
280 static const char* injectedBundleDirectory()
281 {
282 #if ENABLE(DEVELOPER_MODE)
283     const char* bundleDirectory = g_getenv("WEBKIT_INJECTED_BUNDLE_PATH");
284     if (bundleDirectory && g_file_test(bundleDirectory, G_FILE_TEST_IS_DIR))
285         return bundleDirectory;
286 #endif
287
288 #if PLATFORM(GTK)
289     static const char* injectedBundlePath = LIBDIR G_DIR_SEPARATOR_S "webkit2gtk-" WEBKITGTK_API_VERSION_STRING
290         G_DIR_SEPARATOR_S "injected-bundle" G_DIR_SEPARATOR_S;
291     return injectedBundlePath;
292 #elif PLATFORM(WPE)
293     static const char* injectedBundlePath = PKGLIBDIR G_DIR_SEPARATOR_S "injected-bundle" G_DIR_SEPARATOR_S;
294     return injectedBundlePath;
295 #endif
296 }
297
298 static void webkitWebContextGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* paramSpec)
299 {
300     WebKitWebContext* context = WEBKIT_WEB_CONTEXT(object);
301
302     switch (propID) {
303 #if PLATFORM(GTK)
304     case PROP_LOCAL_STORAGE_DIRECTORY:
305         g_value_set_string(value, context->priv->localStorageDirectory.data());
306         break;
307 #endif
308     case PROP_WEBSITE_DATA_MANAGER:
309         g_value_set_object(value, webkit_web_context_get_website_data_manager(context));
310         break;
311     default:
312         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
313     }
314 }
315
316 static void webkitWebContextSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* paramSpec)
317 {
318     WebKitWebContext* context = WEBKIT_WEB_CONTEXT(object);
319
320     switch (propID) {
321 #if PLATFORM(GTK)
322     case PROP_LOCAL_STORAGE_DIRECTORY:
323         context->priv->localStorageDirectory = g_value_get_string(value);
324         break;
325 #endif
326     case PROP_WEBSITE_DATA_MANAGER: {
327         gpointer manager = g_value_get_object(value);
328         context->priv->websiteDataManager = manager ? WEBKIT_WEBSITE_DATA_MANAGER(manager) : nullptr;
329         break;
330     }
331     default:
332         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
333     }
334 }
335
336 static void webkitWebContextConstructed(GObject* object)
337 {
338     G_OBJECT_CLASS(webkit_web_context_parent_class)->constructed(object);
339
340     GUniquePtr<char> bundleFilename(g_build_filename(injectedBundleDirectory(), INJECTED_BUNDLE_FILENAME, nullptr));
341
342     API::ProcessPoolConfiguration configuration;
343     configuration.setInjectedBundlePath(FileSystem::stringFromFileSystemRepresentation(bundleFilename.get()));
344
345     WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(object);
346     WebKitWebContextPrivate* priv = webContext->priv;
347     if (!priv->websiteDataManager)
348         priv->websiteDataManager = adoptGRef(webkit_website_data_manager_new("local-storage-directory", priv->localStorageDirectory.data(), nullptr));
349
350     if (!webkit_website_data_manager_is_ephemeral(priv->websiteDataManager.get()))
351         WebKit::LegacyGlobalSettings::singleton().setHSTSStorageDirectory(FileSystem::stringFromFileSystemRepresentation(webkit_website_data_manager_get_hsts_cache_directory(priv->websiteDataManager.get())));
352
353     priv->processPool = WebProcessPool::create(configuration);
354     priv->processPool->setPrimaryDataStore(webkitWebsiteDataManagerGetDataStore(priv->websiteDataManager.get()));
355
356     webkitWebsiteDataManagerAddProcessPool(priv->websiteDataManager.get(), *priv->processPool);
357
358     priv->tlsErrorsPolicy = WEBKIT_TLS_ERRORS_POLICY_FAIL;
359     priv->processPool->setIgnoreTLSErrors(false);
360
361     priv->processModel = WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES;
362
363 #if ENABLE(MEMORY_SAMPLER)
364     if (getenv("WEBKIT_SAMPLE_MEMORY"))
365         priv->processPool->startMemorySampler(0);
366 #endif
367
368     attachInjectedBundleClientToContext(webContext);
369     attachDownloadClientToContext(webContext);
370
371     priv->geolocationManager = adoptGRef(webkitGeolocationManagerCreate(priv->processPool->supplement<WebGeolocationManagerProxy>()));
372     priv->notificationProvider = makeUnique<WebKitNotificationProvider>(priv->processPool->supplement<WebNotificationManagerProxy>(), webContext);
373 #if PLATFORM(GTK) && ENABLE(REMOTE_INSPECTOR)
374     priv->remoteInspectorProtocolHandler = makeUnique<RemoteInspectorProtocolHandler>(webContext);
375 #endif
376     priv->webkitProtocolHandler = makeUnique<WebKitProtocolHandler>(webContext);
377 }
378
379 static void webkitWebContextDispose(GObject* object)
380 {
381     WebKitWebContextPrivate* priv = WEBKIT_WEB_CONTEXT(object)->priv;
382     if (!priv->clientsDetached) {
383         priv->clientsDetached = true;
384         priv->processPool->setInjectedBundleClient(nullptr);
385         priv->processPool->setDownloadClient(makeUniqueRef<API::DownloadClient>());
386     }
387
388     if (priv->websiteDataManager) {
389         webkitWebsiteDataManagerRemoveProcessPool(priv->websiteDataManager.get(), *priv->processPool);
390         priv->websiteDataManager = nullptr;
391     }
392
393     if (priv->faviconDatabase) {
394         webkitFaviconDatabaseClose(priv->faviconDatabase.get());
395         priv->faviconDatabase = nullptr;
396     }
397
398     G_OBJECT_CLASS(webkit_web_context_parent_class)->dispose(object);
399 }
400
401 static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass)
402 {
403     GObjectClass* gObjectClass = G_OBJECT_CLASS(webContextClass);
404
405     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
406     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
407
408     gObjectClass->get_property = webkitWebContextGetProperty;
409     gObjectClass->set_property = webkitWebContextSetProperty;
410     gObjectClass->constructed = webkitWebContextConstructed;
411     gObjectClass->dispose = webkitWebContextDispose;
412
413 #if PLATFORM(GTK)
414     /**
415      * WebKitWebContext:local-storage-directory:
416      *
417      * The directory where local storage data will be saved.
418      *
419      * Since: 2.8
420      *
421      * Deprecated: 2.10. Use #WebKitWebsiteDataManager:local-storage-directory instead.
422      */
423     g_object_class_install_property(
424         gObjectClass,
425         PROP_LOCAL_STORAGE_DIRECTORY,
426         g_param_spec_string(
427             "local-storage-directory",
428             _("Local Storage Directory"),
429             _("The directory where local storage data will be saved"),
430             nullptr,
431             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
432 #endif
433
434     /**
435      * WebKitWebContext:website-data-manager:
436      *
437      * The #WebKitWebsiteDataManager associated with this context.
438      *
439      * Since: 2.10
440      */
441     g_object_class_install_property(
442         gObjectClass,
443         PROP_WEBSITE_DATA_MANAGER,
444         g_param_spec_object(
445             "website-data-manager",
446             _("Website Data Manager"),
447             _("The WebKitWebsiteDataManager associated with this context"),
448             WEBKIT_TYPE_WEBSITE_DATA_MANAGER,
449             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
450
451     /**
452      * WebKitWebContext::download-started:
453      * @context: the #WebKitWebContext
454      * @download: the #WebKitDownload associated with this event
455      *
456      * This signal is emitted when a new download request is made.
457      */
458     signals[DOWNLOAD_STARTED] =
459         g_signal_new("download-started",
460             G_TYPE_FROM_CLASS(gObjectClass),
461             G_SIGNAL_RUN_LAST,
462             G_STRUCT_OFFSET(WebKitWebContextClass, download_started),
463             nullptr, nullptr,
464             g_cclosure_marshal_VOID__OBJECT,
465             G_TYPE_NONE, 1,
466             WEBKIT_TYPE_DOWNLOAD);
467
468     /**
469      * WebKitWebContext::initialize-web-extensions:
470      * @context: the #WebKitWebContext
471      *
472      * This signal is emitted when a new web process is about to be
473      * launched. It signals the most appropriate moment to use
474      * webkit_web_context_set_web_extensions_initialization_user_data()
475      * and webkit_web_context_set_web_extensions_directory().
476      *
477      * Since: 2.4
478      */
479     signals[INITIALIZE_WEB_EXTENSIONS] =
480         g_signal_new("initialize-web-extensions",
481             G_TYPE_FROM_CLASS(gObjectClass),
482             G_SIGNAL_RUN_LAST,
483             G_STRUCT_OFFSET(WebKitWebContextClass, initialize_web_extensions),
484             nullptr, nullptr,
485             g_cclosure_marshal_VOID__VOID,
486             G_TYPE_NONE, 0);
487
488     /**
489      * WebKitWebContext::initialize-notification-permissions:
490      * @context: the #WebKitWebContext
491      *
492      * This signal is emitted when a #WebKitWebContext needs to set
493      * initial notification permissions for a web process. It is emitted
494      * when a new web process is about to be launched, and signals the
495      * most appropriate moment to use
496      * webkit_web_context_initialize_notification_permissions(). If no
497      * notification permissions have changed since the last time this
498      * signal was emitted, then there is no need to call
499      * webkit_web_context_initialize_notification_permissions() again.
500      *
501      * Since: 2.16
502      */
503     signals[INITIALIZE_NOTIFICATION_PERMISSIONS] =
504         g_signal_new("initialize-notification-permissions",
505             G_TYPE_FROM_CLASS(gObjectClass),
506             G_SIGNAL_RUN_LAST,
507             G_STRUCT_OFFSET(WebKitWebContextClass, initialize_notification_permissions),
508             nullptr, nullptr,
509             g_cclosure_marshal_VOID__VOID,
510             G_TYPE_NONE, 0);
511
512     /**
513      * WebKitWebContext::automation-started:
514      * @context: the #WebKitWebContext
515      * @session: the #WebKitAutomationSession associated with this event
516      *
517      * This signal is emitted when a new automation request is made.
518      * Note that it will never be emitted if automation is not enabled in @context,
519      * see webkit_web_context_set_automation_allowed() for more details.
520      *
521      * Since: 2.18
522      */
523     signals[AUTOMATION_STARTED] =
524         g_signal_new("automation-started",
525             G_TYPE_FROM_CLASS(gObjectClass),
526             G_SIGNAL_RUN_LAST,
527             G_STRUCT_OFFSET(WebKitWebContextClass, automation_started),
528             nullptr, nullptr,
529             g_cclosure_marshal_VOID__OBJECT,
530             G_TYPE_NONE, 1,
531             WEBKIT_TYPE_AUTOMATION_SESSION);
532 }
533
534 static gpointer createDefaultWebContext(gpointer)
535 {
536     static GRefPtr<WebKitWebContext> webContext = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, nullptr)));
537     return webContext.get();
538 }
539
540 /**
541  * webkit_web_context_get_default:
542  *
543  * Gets the default web context
544  *
545  * Returns: (transfer none): a #WebKitWebContext
546  */
547 WebKitWebContext* webkit_web_context_get_default(void)
548 {
549     static GOnce onceInit = G_ONCE_INIT;
550     return WEBKIT_WEB_CONTEXT(g_once(&onceInit, createDefaultWebContext, 0));
551 }
552
553 /**
554  * webkit_web_context_new:
555  *
556  * Create a new #WebKitWebContext
557  *
558  * Returns: (transfer full): a newly created #WebKitWebContext
559  *
560  * Since: 2.8
561  */
562 WebKitWebContext* webkit_web_context_new(void)
563 {
564     return WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, nullptr));
565 }
566
567 /**
568  * webkit_web_context_new_ephemeral:
569  *
570  * Create a new ephemeral #WebKitWebContext. An ephemeral #WebKitWebContext is a context
571  * created with an ephemeral #WebKitWebsiteDataManager. This is just a convenient method
572  * to create ephemeral contexts without having to create your own #WebKitWebsiteDataManager.
573  * All #WebKitWebView<!-- -->s associated with this context will also be ephemeral. Websites will
574  * not store any data in the client storage.
575  * This is normally used to implement private instances.
576  *
577  * Returns: (transfer full): a new ephemeral #WebKitWebContext.
578  *
579  * Since: 2.16
580  */
581 WebKitWebContext* webkit_web_context_new_ephemeral()
582 {
583     GRefPtr<WebKitWebsiteDataManager> manager = adoptGRef(webkit_website_data_manager_new_ephemeral());
584     return WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", manager.get(), nullptr));
585 }
586
587 /**
588  * webkit_web_context_new_with_website_data_manager:
589  * @manager: a #WebKitWebsiteDataManager
590  *
591  * Create a new #WebKitWebContext with a #WebKitWebsiteDataManager.
592  *
593  * Returns: (transfer full): a newly created #WebKitWebContext
594  *
595  * Since: 2.10
596  */
597 WebKitWebContext* webkit_web_context_new_with_website_data_manager(WebKitWebsiteDataManager* manager)
598 {
599     g_return_val_if_fail(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager), nullptr);
600
601     return WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", manager, nullptr));
602 }
603
604 /**
605  * webkit_web_context_get_website_data_manager:
606  * @context: the #WebKitWebContext
607  *
608  * Get the #WebKitWebsiteDataManager of @context.
609  *
610  * Returns: (transfer none): a #WebKitWebsiteDataManager
611  *
612  * Since: 2.10
613  */
614 WebKitWebsiteDataManager* webkit_web_context_get_website_data_manager(WebKitWebContext* context)
615 {
616     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), nullptr);
617
618     return context->priv->websiteDataManager.get();
619 }
620
621 /**
622  * webkit_web_context_is_ephemeral:
623  * @context: the #WebKitWebContext
624  *
625  * Get whether a #WebKitWebContext is ephemeral.
626  *
627  * Returns: %TRUE if @context is ephemeral or %FALSE otherwise.
628  *
629  * Since: 2.16
630  */
631 gboolean webkit_web_context_is_ephemeral(WebKitWebContext* context)
632 {
633     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
634
635     return webkit_website_data_manager_is_ephemeral(context->priv->websiteDataManager.get());
636 }
637
638 /**
639  * webkit_web_context_is_automation_allowed:
640  * @context: the #WebKitWebContext
641  *
642  * Get whether automation is allowed in @context.
643  * See also webkit_web_context_set_automation_allowed().
644  *
645  * Returns: %TRUE if automation is allowed or %FALSE otherwise.
646  *
647  * Since: 2.18
648  */
649 gboolean webkit_web_context_is_automation_allowed(WebKitWebContext* context)
650 {
651     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
652
653 #if ENABLE(REMOTE_INSPECTOR)
654     return !!context->priv->automationClient;
655 #else
656     return FALSE;
657 #endif
658 }
659
660 /**
661  * webkit_web_context_set_automation_allowed:
662  * @context: the #WebKitWebContext
663  * @allowed: value to set
664  *
665  * Set whether automation is allowed in @context. When automation is enabled the browser could
666  * be controlled by another process by requesting an automation session. When a new automation
667  * session is requested the signal #WebKitWebContext::automation-started is emitted.
668  * Automation is disabled by default, so you need to explicitly call this method passing %TRUE
669  * to enable it.
670  *
671  * Note that only one #WebKitWebContext can have automation enabled, so this will do nothing
672  * if there's another #WebKitWebContext with automation already enabled.
673  *
674  * Since: 2.18
675  */
676 void webkit_web_context_set_automation_allowed(WebKitWebContext* context, gboolean allowed)
677 {
678     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
679
680     if (webkit_web_context_is_automation_allowed(context) == allowed)
681         return;
682 #if ENABLE(REMOTE_INSPECTOR)
683     if (allowed) {
684         if (Inspector::RemoteInspector::singleton().client()) {
685             g_warning("Not enabling automation on WebKitWebContext because there's another context with automation enabled, only one is allowed");
686             return;
687         }
688         context->priv->automationClient = makeUnique<WebKitAutomationClient>(context);
689     } else
690         context->priv->automationClient = nullptr;
691 #endif
692 }
693
694 /**
695  * webkit_web_context_set_cache_model:
696  * @context: the #WebKitWebContext
697  * @cache_model: a #WebKitCacheModel
698  *
699  * Specifies a usage model for WebViews, which WebKit will use to
700  * determine its caching behavior. All web views follow the cache
701  * model. This cache model determines the RAM and disk space to use
702  * for caching previously viewed content .
703  *
704  * Research indicates that users tend to browse within clusters of
705  * documents that hold resources in common, and to revisit previously
706  * visited documents. WebKit and the frameworks below it include
707  * built-in caches that take advantage of these patterns,
708  * substantially improving document load speed in browsing
709  * situations. The WebKit cache model controls the behaviors of all of
710  * these caches, including various WebCore caches.
711  *
712  * Browsers can improve document load speed substantially by
713  * specifying %WEBKIT_CACHE_MODEL_WEB_BROWSER. Applications without a
714  * browsing interface can reduce memory usage substantially by
715  * specifying %WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER. The default value is
716  * %WEBKIT_CACHE_MODEL_WEB_BROWSER.
717  */
718 void webkit_web_context_set_cache_model(WebKitWebContext*, WebKitCacheModel model)
719 {
720     CacheModel cacheModel;
721
722     switch (model) {
723     case WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER:
724         cacheModel = CacheModel::DocumentViewer;
725         break;
726     case WEBKIT_CACHE_MODEL_WEB_BROWSER:
727         cacheModel = CacheModel::PrimaryWebBrowser;
728         break;
729     case WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER:
730         cacheModel = CacheModel::DocumentBrowser;
731         break;
732     default:
733         g_assert_not_reached();
734     }
735
736     if (cacheModel != LegacyGlobalSettings::singleton().cacheModel())
737         LegacyGlobalSettings::singleton().setCacheModel(cacheModel);
738 }
739
740 /**
741  * webkit_web_context_get_cache_model:
742  * @context: the #WebKitWebContext
743  *
744  * Returns the current cache model. For more information about this
745  * value check the documentation of the function
746  * webkit_web_context_set_cache_model().
747  *
748  * Returns: the current #WebKitCacheModel
749  */
750 WebKitCacheModel webkit_web_context_get_cache_model(WebKitWebContext* context)
751 {
752     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_CACHE_MODEL_WEB_BROWSER);
753
754     switch (LegacyGlobalSettings::singleton().cacheModel()) {
755     case CacheModel::DocumentViewer:
756         return WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER;
757     case CacheModel::PrimaryWebBrowser:
758         return WEBKIT_CACHE_MODEL_WEB_BROWSER;
759     case CacheModel::DocumentBrowser:
760         return WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER;
761     default:
762         g_assert_not_reached();
763     }
764
765     return WEBKIT_CACHE_MODEL_WEB_BROWSER;
766 }
767
768 /**
769  * webkit_web_context_clear_cache:
770  * @context: a #WebKitWebContext
771  *
772  * Clears all resources currently cached.
773  * See also webkit_web_context_set_cache_model().
774  */
775 void webkit_web_context_clear_cache(WebKitWebContext* context)
776 {
777     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
778
779     OptionSet<WebsiteDataType> websiteDataTypes;
780     websiteDataTypes.add(WebsiteDataType::MemoryCache);
781     websiteDataTypes.add(WebsiteDataType::DiskCache);
782     auto& websiteDataStore = webkitWebsiteDataManagerGetDataStore(context->priv->websiteDataManager.get());
783     websiteDataStore.removeData(websiteDataTypes, -WallTime::infinity(), [] { });
784 }
785
786 /**
787  * webkit_web_context_set_network_proxy_settings:
788  * @context: a #WebKitWebContext
789  * @proxy_mode: a #WebKitNetworkProxyMode
790  * @proxy_settings: (allow-none): a #WebKitNetworkProxySettings, or %NULL
791  *
792  * Set the network proxy settings to be used by connections started in @context.
793  * By default %WEBKIT_NETWORK_PROXY_MODE_DEFAULT is used, which means that the
794  * system settings will be used (g_proxy_resolver_get_default()).
795  * If you want to override the system default settings, you can either use
796  * %WEBKIT_NETWORK_PROXY_MODE_NO_PROXY to make sure no proxies are used at all,
797  * or %WEBKIT_NETWORK_PROXY_MODE_CUSTOM to provide your own proxy settings.
798  * When @proxy_mode is %WEBKIT_NETWORK_PROXY_MODE_CUSTOM @proxy_settings must be
799  * a valid #WebKitNetworkProxySettings; otherwise, @proxy_settings must be %NULL.
800  *
801  * Since: 2.16
802  */
803 void webkit_web_context_set_network_proxy_settings(WebKitWebContext* context, WebKitNetworkProxyMode proxyMode, WebKitNetworkProxySettings* proxySettings)
804 {
805     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
806     g_return_if_fail((proxyMode != WEBKIT_NETWORK_PROXY_MODE_CUSTOM && !proxySettings) || (proxyMode == WEBKIT_NETWORK_PROXY_MODE_CUSTOM && proxySettings));
807
808     WebKitWebContextPrivate* priv = context->priv;
809     switch (proxyMode) {
810     case WEBKIT_NETWORK_PROXY_MODE_DEFAULT:
811         priv->processPool->setNetworkProxySettings({ });
812         break;
813     case WEBKIT_NETWORK_PROXY_MODE_NO_PROXY:
814         priv->processPool->setNetworkProxySettings(WebCore::SoupNetworkProxySettings(WebCore::SoupNetworkProxySettings::Mode::NoProxy));
815         break;
816     case WEBKIT_NETWORK_PROXY_MODE_CUSTOM:
817         const auto& settings = webkitNetworkProxySettingsGetNetworkProxySettings(proxySettings);
818         if (settings.isEmpty()) {
819             g_warning("Invalid attempt to set custom network proxy settings with an empty WebKitNetworkProxySettings. Use "
820                 "WEBKIT_NETWORK_PROXY_MODE_NO_PROXY to not use any proxy or WEBKIT_NETWORK_PROXY_MODE_DEFAULT to use the default system settings");
821         } else
822             priv->processPool->setNetworkProxySettings(settings);
823         break;
824     }
825 }
826
827 typedef HashMap<DownloadProxy*, GRefPtr<WebKitDownload> > DownloadsMap;
828
829 static DownloadsMap& downloadsMap()
830 {
831     static NeverDestroyed<DownloadsMap> downloads;
832     return downloads;
833 }
834
835 /**
836  * webkit_web_context_download_uri:
837  * @context: a #WebKitWebContext
838  * @uri: the URI to download
839  *
840  * Requests downloading of the specified URI string. The download operation
841  * will not be associated to any #WebKitWebView, if you are interested in
842  * starting a download from a particular #WebKitWebView use
843  * webkit_web_view_download_uri() instead.
844  *
845  * Returns: (transfer full): a new #WebKitDownload representing
846  *    the download operation.
847  */
848 WebKitDownload* webkit_web_context_download_uri(WebKitWebContext* context, const gchar* uri)
849 {
850     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), nullptr);
851     g_return_val_if_fail(uri, nullptr);
852
853     GRefPtr<WebKitDownload> download = webkitWebContextStartDownload(context, uri, nullptr);
854     return download.leakRef();
855 }
856
857 /**
858  * webkit_web_context_get_cookie_manager:
859  * @context: a #WebKitWebContext
860  *
861  * Get the #WebKitCookieManager of the @context's #WebKitWebsiteDataManager.
862  *
863  * Returns: (transfer none): the #WebKitCookieManager of @context.
864  */
865 WebKitCookieManager* webkit_web_context_get_cookie_manager(WebKitWebContext* context)
866 {
867     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), nullptr);
868
869     return webkit_website_data_manager_get_cookie_manager(context->priv->websiteDataManager.get());
870 }
871
872 /**
873  * webkit_web_context_get_geolocation_manager:
874  * @context: a #WebKitWebContext
875  *
876  * Get the #WebKitGeolocationManager of @context.
877  *
878  * Returns: (transfer none): the #WebKitGeolocationManager of @context.
879  *
880  * Since: 2.26
881  */
882 WebKitGeolocationManager* webkit_web_context_get_geolocation_manager(WebKitWebContext* context)
883 {
884     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), nullptr);
885
886     return context->priv->geolocationManager.get();
887 }
888
889 static void ensureFaviconDatabase(WebKitWebContext* context)
890 {
891     WebKitWebContextPrivate* priv = context->priv;
892     if (priv->faviconDatabase)
893         return;
894
895     priv->faviconDatabase = adoptGRef(webkitFaviconDatabaseCreate());
896 }
897
898 /**
899  * webkit_web_context_set_favicon_database_directory:
900  * @context: a #WebKitWebContext
901  * @path: (allow-none): an absolute path to the icon database
902  * directory or %NULL to use the defaults
903  *
904  * Set the directory path to be used to store the favicons database
905  * for @context on disk. Passing %NULL as @path means using the
906  * default directory for the platform (see g_get_user_cache_dir()).
907  *
908  * Calling this method also means enabling the favicons database for
909  * its use from the applications, so that's why it's expected to be
910  * called only once. Further calls for the same instance of
911  * #WebKitWebContext won't cause any effect.
912  */
913 void webkit_web_context_set_favicon_database_directory(WebKitWebContext* context, const gchar* path)
914 {
915     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
916
917     WebKitWebContextPrivate* priv = context->priv;
918     ensureFaviconDatabase(context);
919
920     String directoryPath = FileSystem::stringFromFileSystemRepresentation(path);
921     // Use default if nullptr is passed as parameter.
922     if (directoryPath.isEmpty()) {
923 #if PLATFORM(GTK)
924         const char* portDirectory = "webkitgtk";
925 #elif PLATFORM(WPE)
926         const char* portDirectory = "wpe";
927 #endif
928         GUniquePtr<gchar> databaseDirectory(g_build_filename(g_get_user_cache_dir(), portDirectory, "icondatabase", nullptr));
929         directoryPath = FileSystem::stringFromFileSystemRepresentation(databaseDirectory.get());
930     }
931     priv->faviconDatabaseDirectory = directoryPath.utf8();
932
933     // Build the full path to the icon database file on disk.
934     GUniquePtr<gchar> faviconDatabasePath(g_build_filename(priv->faviconDatabaseDirectory.data(),
935         "WebpageIcons.db", nullptr));
936
937     // Setting the path will cause the icon database to be opened.
938     webkitFaviconDatabaseOpen(priv->faviconDatabase.get(), FileSystem::stringFromFileSystemRepresentation(faviconDatabasePath.get()), webkit_web_context_is_ephemeral(context));
939 }
940
941 /**
942  * webkit_web_context_get_favicon_database_directory:
943  * @context: a #WebKitWebContext
944  *
945  * Get the directory path being used to store the favicons database
946  * for @context, or %NULL if
947  * webkit_web_context_set_favicon_database_directory() hasn't been
948  * called yet.
949  *
950  * This function will always return the same path after having called
951  * webkit_web_context_set_favicon_database_directory() for the first
952  * time.
953  *
954  * Returns: (transfer none): the path of the directory of the favicons
955  * database associated with @context, or %NULL.
956  */
957 const gchar* webkit_web_context_get_favicon_database_directory(WebKitWebContext *context)
958 {
959     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
960
961     WebKitWebContextPrivate* priv = context->priv;
962     if (priv->faviconDatabaseDirectory.isNull())
963         return 0;
964
965     return priv->faviconDatabaseDirectory.data();
966 }
967
968 /**
969  * webkit_web_context_get_favicon_database:
970  * @context: a #WebKitWebContext
971  *
972  * Get the #WebKitFaviconDatabase associated with @context.
973  *
974  * To initialize the database you need to call
975  * webkit_web_context_set_favicon_database_directory().
976  *
977  * Returns: (transfer none): the #WebKitFaviconDatabase of @context.
978  */
979 WebKitFaviconDatabase* webkit_web_context_get_favicon_database(WebKitWebContext* context)
980 {
981     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
982
983     ensureFaviconDatabase(context);
984     return context->priv->faviconDatabase.get();
985 }
986
987 /**
988  * webkit_web_context_get_security_manager:
989  * @context: a #WebKitWebContext
990  *
991  * Get the #WebKitSecurityManager of @context.
992  *
993  * Returns: (transfer none): the #WebKitSecurityManager of @context.
994  */
995 WebKitSecurityManager* webkit_web_context_get_security_manager(WebKitWebContext* context)
996 {
997     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
998
999     WebKitWebContextPrivate* priv = context->priv;
1000     if (!priv->securityManager)
1001         priv->securityManager = adoptGRef(webkitSecurityManagerCreate(context));
1002
1003     return priv->securityManager.get();
1004 }
1005
1006 /**
1007  * webkit_web_context_set_additional_plugins_directory:
1008  * @context: a #WebKitWebContext
1009  * @directory: the directory to add
1010  *
1011  * Set an additional directory where WebKit will look for plugins.
1012  */
1013 void webkit_web_context_set_additional_plugins_directory(WebKitWebContext* context, const char* directory)
1014 {
1015     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1016     g_return_if_fail(directory);
1017
1018 #if ENABLE(NETSCAPE_PLUGIN_API)
1019     context->priv->processPool->setAdditionalPluginsDirectory(FileSystem::stringFromFileSystemRepresentation(directory));
1020 #endif
1021 }
1022
1023 static void destroyPluginList(GList* plugins)
1024 {
1025     g_list_free_full(plugins, g_object_unref);
1026 }
1027
1028 static void webkitWebContextGetPluginThread(GTask* task, gpointer object, gpointer /* taskData */, GCancellable*)
1029 {
1030     GList* returnValue = 0;
1031 #if ENABLE(NETSCAPE_PLUGIN_API)
1032     Vector<PluginModuleInfo> plugins = WEBKIT_WEB_CONTEXT(object)->priv->processPool->pluginInfoStore().plugins();
1033     for (size_t i = 0; i < plugins.size(); ++i)
1034         returnValue = g_list_prepend(returnValue, webkitPluginCreate(plugins[i]));
1035 #endif
1036     g_task_return_pointer(task, returnValue, reinterpret_cast<GDestroyNotify>(destroyPluginList));
1037 }
1038
1039 /**
1040  * webkit_web_context_get_plugins:
1041  * @context: a #WebKitWebContext
1042  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
1043  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
1044  * @user_data: (closure): the data to pass to callback function
1045  *
1046  * Asynchronously get the list of installed plugins.
1047  *
1048  * When the operation is finished, @callback will be called. You can then call
1049  * webkit_web_context_get_plugins_finish() to get the result of the operation.
1050  */
1051 void webkit_web_context_get_plugins(WebKitWebContext* context, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
1052 {
1053     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1054
1055     GRefPtr<GTask> task = adoptGRef(g_task_new(context, cancellable, callback, userData));
1056     g_task_run_in_thread(task.get(), webkitWebContextGetPluginThread);
1057 }
1058
1059 /**
1060  * webkit_web_context_get_plugins_finish:
1061  * @context: a #WebKitWebContext
1062  * @result: a #GAsyncResult
1063  * @error: return location for error or %NULL to ignore
1064  *
1065  * Finish an asynchronous operation started with webkit_web_context_get_plugins.
1066  *
1067  * Returns: (element-type WebKitPlugin) (transfer full): a #GList of #WebKitPlugin. You must free the #GList with
1068  *    g_list_free() and unref the #WebKitPlugin<!-- -->s with g_object_unref() when you're done with them.
1069  */
1070 GList* webkit_web_context_get_plugins_finish(WebKitWebContext* context, GAsyncResult* result, GError** error)
1071 {
1072     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
1073     g_return_val_if_fail(g_task_is_valid(result, context), 0);
1074
1075     return static_cast<GList*>(g_task_propagate_pointer(G_TASK(result), error));
1076 }
1077
1078 /**
1079  * webkit_web_context_register_uri_scheme:
1080  * @context: a #WebKitWebContext
1081  * @scheme: the network scheme to register
1082  * @callback: (scope async): a #WebKitURISchemeRequestCallback
1083  * @user_data: data to pass to callback function
1084  * @user_data_destroy_func: destroy notify for @user_data
1085  *
1086  * Register @scheme in @context, so that when an URI request with @scheme is made in the
1087  * #WebKitWebContext, the #WebKitURISchemeRequestCallback registered will be called with a
1088  * #WebKitURISchemeRequest.
1089  * It is possible to handle URI scheme requests asynchronously, by calling g_object_ref() on the
1090  * #WebKitURISchemeRequest and calling webkit_uri_scheme_request_finish() later
1091  * when the data of the request is available or
1092  * webkit_uri_scheme_request_finish_error() in case of error.
1093  *
1094  * <informalexample><programlisting>
1095  * static void
1096  * about_uri_scheme_request_cb (WebKitURISchemeRequest *request,
1097  *                              gpointer                user_data)
1098  * {
1099  *     GInputStream *stream;
1100  *     gsize         stream_length;
1101  *     const gchar  *path;
1102  *
1103  *     path = webkit_uri_scheme_request_get_path (request);
1104  *     if (!g_strcmp0 (path, "plugins")) {
1105  *         /<!-- -->* Create a GInputStream with the contents of plugins about page, and set its length to stream_length *<!-- -->/
1106  *     } else if (!g_strcmp0 (path, "memory")) {
1107  *         /<!-- -->* Create a GInputStream with the contents of memory about page, and set its length to stream_length *<!-- -->/
1108  *     } else if (!g_strcmp0 (path, "applications")) {
1109  *         /<!-- -->* Create a GInputStream with the contents of applications about page, and set its length to stream_length *<!-- -->/
1110  *     } else if (!g_strcmp0 (path, "example")) {
1111  *         gchar *contents;
1112  *
1113  *         contents = g_strdup_printf ("&lt;html&gt;&lt;body&gt;&lt;p&gt;Example about page&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;");
1114  *         stream_length = strlen (contents);
1115  *         stream = g_memory_input_stream_new_from_data (contents, stream_length, g_free);
1116  *     } else {
1117  *         GError *error;
1118  *
1119  *         error = g_error_new (ABOUT_HANDLER_ERROR, ABOUT_HANDLER_ERROR_INVALID, "Invalid about:%s page.", path);
1120  *         webkit_uri_scheme_request_finish_error (request, error);
1121  *         g_error_free (error);
1122  *         return;
1123  *     }
1124  *     webkit_uri_scheme_request_finish (request, stream, stream_length, "text/html");
1125  *     g_object_unref (stream);
1126  * }
1127  * </programlisting></informalexample>
1128  */
1129 void webkit_web_context_register_uri_scheme(WebKitWebContext* context, const char* scheme, WebKitURISchemeRequestCallback callback, gpointer userData, GDestroyNotify destroyNotify)
1130 {
1131     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1132     g_return_if_fail(scheme);
1133     g_return_if_fail(callback);
1134
1135     auto handler = WebKitURISchemeHandler::create(context, callback, userData, destroyNotify);
1136     auto addResult = context->priv->uriSchemeHandlers.set(String::fromUTF8(scheme), WTFMove(handler));
1137     for (auto* webView : context->priv->webViews.values())
1138         webkitWebViewGetPage(webView).setURLSchemeHandlerForScheme(*addResult.iterator->value, String::fromUTF8(scheme));
1139 }
1140
1141 /**
1142  * webkit_web_context_set_sandbox_enabled:
1143  * @context: a #WebKitWebContext
1144  * @enabled: if %TRUE enable sandboxing
1145  *
1146  * Set whether WebKit subprocesses will be sandboxed, limiting access to the system.
1147  *
1148  * This method **must be called before any web process has been created**,
1149  * as early as possible in your application. Calling it later is a fatal error.
1150  *
1151  * This is only implemented on Linux and is a no-op otherwise.
1152  *
1153  * Since: 2.26
1154  */
1155 void webkit_web_context_set_sandbox_enabled(WebKitWebContext* context, gboolean enabled)
1156 {
1157     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1158
1159     if (context->priv->processPool->processes().size())
1160         g_error("Sandboxing cannot be changed after subprocesses were spawned.");
1161
1162     context->priv->processPool->setSandboxEnabled(enabled);
1163 }
1164
1165 static bool pathIsBlacklisted(const char* path)
1166 {
1167     static const Vector<CString, 4> blacklistedPrefixes = {
1168         // These are recreated by bwrap and it doesn't make sense to try and rebind them.
1169         "sys", "proc", "dev",
1170         "", // All of `/` isn't acceptable.
1171     };
1172
1173     if (!g_path_is_absolute(path))
1174         return true;
1175
1176     GUniquePtr<char*> splitPath(g_strsplit(path, G_DIR_SEPARATOR_S, 3));
1177     return blacklistedPrefixes.contains(splitPath.get()[1]);
1178 }
1179
1180 /**
1181  * webkit_web_context_add_path_to_sandbox:
1182  * @context: a #WebKitWebContext
1183  * @path: (type filename): an absolute path to mount in the sandbox
1184  * @read_only: if %TRUE the path will be read-only
1185  *
1186  * Adds a path to be mounted in the sandbox. @path must exist before any web process
1187  * has been created otherwise it will be silently ignored. It is a fatal error to
1188  * add paths after a web process has been spawned.
1189  *
1190  * Paths in directories such as `/sys`, `/proc`, and `/dev` or all of `/`
1191  * are not valid.
1192  *
1193  * See also webkit_web_context_set_sandbox_enabled()
1194  *
1195  * Since: 2.26
1196  */
1197 void webkit_web_context_add_path_to_sandbox(WebKitWebContext* context, const char* path, gboolean readOnly)
1198 {
1199     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1200
1201     if (pathIsBlacklisted(path)) {
1202         g_critical("Attempted to add disallowed path to sandbox: %s", path);
1203         return;
1204     }
1205
1206     if (context->priv->processPool->processes().size())
1207         g_error("Sandbox paths cannot be changed after subprocesses were spawned.");
1208
1209     auto permission = readOnly ? SandboxPermission::ReadOnly : SandboxPermission::ReadWrite;
1210     context->priv->processPool->addSandboxPath(path, permission);
1211 }
1212
1213 /**
1214  * webkit_web_context_get_sandbox_enabled:
1215  * @context: a #WebKitWebContext
1216  *
1217  * Get whether sandboxing is currently enabled.
1218  *
1219  * Returns: %TRUE if sandboxing is enabled, or %FALSE otherwise.
1220  *
1221  * Since: 2.26
1222  */
1223 gboolean webkit_web_context_get_sandbox_enabled(WebKitWebContext* context)
1224 {
1225     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
1226
1227     return context->priv->processPool->sandboxEnabled();
1228 }
1229
1230 /**
1231  * webkit_web_context_get_spell_checking_enabled:
1232  * @context: a #WebKitWebContext
1233  *
1234  * Get whether spell checking feature is currently enabled.
1235  *
1236  * Returns: %TRUE If spell checking is enabled, or %FALSE otherwise.
1237  */
1238 gboolean webkit_web_context_get_spell_checking_enabled(WebKitWebContext* context)
1239 {
1240     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
1241
1242 #if ENABLE(SPELLCHECK)
1243     return TextChecker::state().isContinuousSpellCheckingEnabled;
1244 #else
1245     return false;
1246 #endif
1247 }
1248
1249 /**
1250  * webkit_web_context_set_spell_checking_enabled:
1251  * @context: a #WebKitWebContext
1252  * @enabled: Value to be set
1253  *
1254  * Enable or disable the spell checking feature.
1255  */
1256 void webkit_web_context_set_spell_checking_enabled(WebKitWebContext* context, gboolean enabled)
1257 {
1258     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1259
1260 #if ENABLE(SPELLCHECK)
1261     TextChecker::setContinuousSpellCheckingEnabled(enabled);
1262 #endif
1263 }
1264
1265 /**
1266  * webkit_web_context_get_spell_checking_languages:
1267  * @context: a #WebKitWebContext
1268  *
1269  * Get the the list of spell checking languages associated with
1270  * @context, or %NULL if no languages have been previously set.
1271  *
1272  * See webkit_web_context_set_spell_checking_languages() for more
1273  * details on the format of the languages in the list.
1274  *
1275  * Returns: (array zero-terminated=1) (element-type utf8) (transfer none): A %NULL-terminated
1276  *    array of languages if available, or %NULL otherwise.
1277  */
1278 const gchar* const* webkit_web_context_get_spell_checking_languages(WebKitWebContext* context)
1279 {
1280     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), nullptr);
1281
1282 #if ENABLE(SPELLCHECK)
1283     Vector<String> spellCheckingLanguages = TextChecker::loadedSpellCheckingLanguages();
1284     if (spellCheckingLanguages.isEmpty())
1285         return nullptr;
1286
1287     static GRefPtr<GPtrArray> languagesToReturn;
1288     languagesToReturn = adoptGRef(g_ptr_array_new_with_free_func(g_free));
1289     for (const auto& language : spellCheckingLanguages)
1290         g_ptr_array_add(languagesToReturn.get(), g_strdup(language.utf8().data()));
1291     g_ptr_array_add(languagesToReturn.get(), nullptr);
1292
1293     return reinterpret_cast<char**>(languagesToReturn->pdata);
1294 #else
1295     return 0;
1296 #endif
1297 }
1298
1299 /**
1300  * webkit_web_context_set_spell_checking_languages:
1301  * @context: a #WebKitWebContext
1302  * @languages: (array zero-terminated=1) (transfer none): a %NULL-terminated list of spell checking languages
1303  *
1304  * Set the list of spell checking languages to be used for spell
1305  * checking.
1306  *
1307  * The locale string typically is in the form lang_COUNTRY, where lang
1308  * is an ISO-639 language code, and COUNTRY is an ISO-3166 country code.
1309  * For instance, sv_FI for Swedish as written in Finland or pt_BR
1310  * for Portuguese as written in Brazil.
1311  *
1312  * You need to call this function with a valid list of languages at
1313  * least once in order to properly enable the spell checking feature
1314  * in WebKit.
1315  */
1316 void webkit_web_context_set_spell_checking_languages(WebKitWebContext* context, const gchar* const* languages)
1317 {
1318     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1319     g_return_if_fail(languages);
1320
1321 #if ENABLE(SPELLCHECK)
1322     Vector<String> spellCheckingLanguages;
1323     for (size_t i = 0; languages[i]; ++i)
1324         spellCheckingLanguages.append(String::fromUTF8(languages[i]));
1325     TextChecker::setSpellCheckingLanguages(spellCheckingLanguages);
1326 #endif
1327 }
1328
1329 /**
1330  * webkit_web_context_set_preferred_languages:
1331  * @context: a #WebKitWebContext
1332  * @languages: (allow-none) (array zero-terminated=1) (element-type utf8) (transfer none): a %NULL-terminated list of language identifiers
1333  *
1334  * Set the list of preferred languages, sorted from most desirable
1335  * to least desirable. The list will be used to build the "Accept-Language"
1336  * header that will be included in the network requests started by
1337  * the #WebKitWebContext.
1338  */
1339 void webkit_web_context_set_preferred_languages(WebKitWebContext* context, const gchar* const* languageList)
1340 {
1341     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1342
1343     if (!languageList || !g_strv_length(const_cast<char**>(languageList)))
1344         return;
1345
1346     Vector<String> languages;
1347     for (size_t i = 0; languageList[i]; ++i) {
1348         // Do not propagate the C locale to WebCore.
1349         if (!g_ascii_strcasecmp(languageList[i], "C") || !g_ascii_strcasecmp(languageList[i], "POSIX"))
1350             languages.append("en-US"_s);
1351         else
1352             languages.append(String::fromUTF8(languageList[i]).replace("_", "-"));
1353     }
1354     overrideUserPreferredLanguages(languages);
1355 }
1356
1357 /**
1358  * webkit_web_context_set_tls_errors_policy:
1359  * @context: a #WebKitWebContext
1360  * @policy: a #WebKitTLSErrorsPolicy
1361  *
1362  * Set the TLS errors policy of @context as @policy
1363  */
1364 void webkit_web_context_set_tls_errors_policy(WebKitWebContext* context, WebKitTLSErrorsPolicy policy)
1365 {
1366     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1367
1368     if (context->priv->tlsErrorsPolicy == policy)
1369         return;
1370
1371     context->priv->tlsErrorsPolicy = policy;
1372     bool ignoreTLSErrors = policy == WEBKIT_TLS_ERRORS_POLICY_IGNORE;
1373     if (context->priv->processPool->ignoreTLSErrors() != ignoreTLSErrors)
1374         context->priv->processPool->setIgnoreTLSErrors(ignoreTLSErrors);
1375 }
1376
1377 /**
1378  * webkit_web_context_get_tls_errors_policy:
1379  * @context: a #WebKitWebContext
1380  *
1381  * Get the TLS errors policy of @context
1382  *
1383  * Returns: a #WebKitTLSErrorsPolicy
1384  */
1385 WebKitTLSErrorsPolicy webkit_web_context_get_tls_errors_policy(WebKitWebContext* context)
1386 {
1387     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_TLS_ERRORS_POLICY_IGNORE);
1388
1389     return context->priv->tlsErrorsPolicy;
1390 }
1391
1392 /**
1393  * webkit_web_context_set_web_extensions_directory:
1394  * @context: a #WebKitWebContext
1395  * @directory: the directory to add
1396  *
1397  * Set the directory where WebKit will look for Web Extensions.
1398  * This method must be called before loading anything in this context,
1399  * otherwise it will not have any effect. You can connect to
1400  * #WebKitWebContext::initialize-web-extensions to call this method
1401  * before anything is loaded.
1402  */
1403 void webkit_web_context_set_web_extensions_directory(WebKitWebContext* context, const char* directory)
1404 {
1405     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1406     g_return_if_fail(directory);
1407
1408     context->priv->webExtensionsDirectory = directory;
1409     context->priv->processPool->addSandboxPath(directory, SandboxPermission::ReadOnly);
1410 }
1411
1412 /**
1413  * webkit_web_context_set_web_extensions_initialization_user_data:
1414  * @context: a #WebKitWebContext
1415  * @user_data: a #GVariant
1416  *
1417  * Set user data to be passed to Web Extensions on initialization.
1418  * The data will be passed to the
1419  * #WebKitWebExtensionInitializeWithUserDataFunction.
1420  * This method must be called before loading anything in this context,
1421  * otherwise it will not have any effect. You can connect to
1422  * #WebKitWebContext::initialize-web-extensions to call this method
1423  * before anything is loaded.
1424  *
1425  * Since: 2.4
1426  */
1427 void webkit_web_context_set_web_extensions_initialization_user_data(WebKitWebContext* context, GVariant* userData)
1428 {
1429     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1430     g_return_if_fail(userData);
1431
1432     context->priv->webExtensionsInitializationUserData = userData;
1433 }
1434
1435 #if PLATFORM(GTK)
1436 /**
1437  * webkit_web_context_set_disk_cache_directory:
1438  * @context: a #WebKitWebContext
1439  * @directory: the directory to set
1440  *
1441  * Set the directory where disk cache files will be stored
1442  * This method must be called before loading anything in this context, otherwise
1443  * it will not have any effect.
1444  *
1445  * Note that this method overrides the directory set in the #WebKitWebsiteDataManager,
1446  * but it doesn't change the value returned by webkit_website_data_manager_get_disk_cache_directory()
1447  * since the #WebKitWebsiteDataManager is immutable.
1448  *
1449  * Deprecated: 2.10. Use webkit_web_context_new_with_website_data_manager() instead.
1450  */
1451 void webkit_web_context_set_disk_cache_directory(WebKitWebContext*, const char*)
1452 {
1453     g_warning("webkit_web_context_set_disk_cache_directory is deprecated and does nothing, use WebKitWebsiteDataManager instead");
1454 }
1455 #endif
1456
1457 /**
1458  * webkit_web_context_prefetch_dns:
1459  * @context: a #WebKitWebContext
1460  * @hostname: a hostname to be resolved
1461  *
1462  * Resolve the domain name of the given @hostname in advance, so that if a URI
1463  * of @hostname is requested the load will be performed more quickly.
1464  */
1465 void webkit_web_context_prefetch_dns(WebKitWebContext* context, const char* hostname)
1466 {
1467     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1468     g_return_if_fail(hostname);
1469
1470     API::Dictionary::MapType message;
1471     message.set(String::fromUTF8("Hostname"), API::String::create(String::fromUTF8(hostname)));
1472     context->priv->processPool->postMessageToInjectedBundle(String::fromUTF8("PrefetchDNS"), API::Dictionary::create(WTFMove(message)).ptr());
1473 }
1474
1475 /**
1476  * webkit_web_context_allow_tls_certificate_for_host:
1477  * @context: a #WebKitWebContext
1478  * @certificate: a #GTlsCertificate
1479  * @host: the host for which a certificate is to be allowed
1480  *
1481  * Ignore further TLS errors on the @host for the certificate present in @info.
1482  *
1483  * Since: 2.6
1484  */
1485 void webkit_web_context_allow_tls_certificate_for_host(WebKitWebContext* context, GTlsCertificate* certificate, const gchar* host)
1486 {
1487     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1488     g_return_if_fail(G_IS_TLS_CERTIFICATE(certificate));
1489     g_return_if_fail(host);
1490
1491     auto webCertificateInfo = WebCertificateInfo::create(WebCore::CertificateInfo(certificate, static_cast<GTlsCertificateFlags>(0)));
1492     context->priv->processPool->allowSpecificHTTPSCertificateForHost(webCertificateInfo.ptr(), String::fromUTF8(host));
1493 }
1494
1495 /**
1496  * webkit_web_context_set_process_model:
1497  * @context: the #WebKitWebContext
1498  * @process_model: a #WebKitProcessModel
1499  *
1500  * Specifies a process model for WebViews, which WebKit will use to
1501  * determine how auxiliary processes are handled.
1502  *
1503  * %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES will use
1504  * one process per view most of the time, while still allowing for web
1505  * views to share a process when needed (for example when different
1506  * views interact with each other). Using this model, when a process
1507  * hangs or crashes, only the WebViews using it stop working, while
1508  * the rest of the WebViews in the application will still function
1509  * normally.
1510  *
1511  * %WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS is deprecated since 2.26,
1512  * using it has no effect for security reasons.
1513  *
1514  * This method **must be called before any web process has been created**,
1515  * as early as possible in your application. Calling it later will make
1516  * your application crash.
1517  *
1518  * Since: 2.4
1519  */
1520 void webkit_web_context_set_process_model(WebKitWebContext* context, WebKitProcessModel processModel)
1521 {
1522     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1523
1524     if (processModel == WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS) {
1525         g_warning("WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS is deprecated and has no effect");
1526         return;
1527     }
1528
1529     if (processModel == context->priv->processModel)
1530         return;
1531
1532     context->priv->processModel = processModel;
1533 }
1534
1535 /**
1536  * webkit_web_context_get_process_model:
1537  * @context: the #WebKitWebContext
1538  *
1539  * Returns the current process model. For more information about this value
1540  * see webkit_web_context_set_process_model().
1541  *
1542  * Returns: the current #WebKitProcessModel
1543  *
1544  * Since: 2.4
1545  */
1546 WebKitProcessModel webkit_web_context_get_process_model(WebKitWebContext* context)
1547 {
1548     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
1549
1550     return context->priv->processModel;
1551 }
1552
1553 /**
1554  * webkit_web_context_set_web_process_count_limit:
1555  * @context: the #WebKitWebContext
1556  * @limit: the maximum number of web processes
1557  *
1558  * Sets the maximum number of web processes that can be created at the same time for the @context.
1559  * The default value is 0 and means no limit.
1560  *
1561  * This function is now deprecated and does nothing for security reasons.
1562  *
1563  * Since: 2.10
1564  *
1565  * Deprecated: 2.26
1566  */
1567 void webkit_web_context_set_web_process_count_limit(WebKitWebContext* context, guint limit)
1568 {
1569     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
1570
1571     g_warning("webkit_web_context_set_web_process_count_limit is deprecated and does nothing. Limiting the number of web processes is no longer possible for security reasons");
1572 }
1573
1574 /**
1575  * webkit_web_context_get_web_process_count_limit:
1576  * @context: the #WebKitWebContext
1577  *
1578  * Gets the maximum number of web processes that can be created at the same time for the @context.
1579  *
1580  * This function is now deprecated and always returns 0 (no limit). See also webkit_web_context_set_web_process_count_limit().
1581  *
1582  * Returns: the maximum limit of web processes, or 0 if there isn't a limit.
1583  *
1584  * Since: 2.10
1585  *
1586  * Deprecated: 2.26
1587  */
1588 guint webkit_web_context_get_web_process_count_limit(WebKitWebContext* context)
1589 {
1590     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
1591
1592     return 0;
1593 }
1594
1595 static void addOriginToMap(WebKitSecurityOrigin* origin, HashMap<String, bool>* map, bool allowed)
1596 {
1597     String string = webkitSecurityOriginGetSecurityOrigin(origin).toString();
1598     if (string != "null")
1599         map->set(string, allowed);
1600 }
1601
1602 /**
1603  * webkit_web_context_initialize_notification_permissions:
1604  * @context: the #WebKitWebContext
1605  * @allowed_origins: (element-type WebKitSecurityOrigin): a #GList of security origins
1606  * @disallowed_origins: (element-type WebKitSecurityOrigin): a #GList of security origins
1607  *
1608  * Sets initial desktop notification permissions for the @context.
1609  * @allowed_origins and @disallowed_origins must each be #GList of
1610  * #WebKitSecurityOrigin objects representing origins that will,
1611  * respectively, either always or never have permission to show desktop
1612  * notifications. No #WebKitNotificationPermissionRequest will ever be
1613  * generated for any of the security origins represented in
1614  * @allowed_origins or @disallowed_origins. This function is necessary
1615  * because some webpages proactively check whether they have permission
1616  * to display notifications without ever creating a permission request.
1617  *
1618  * This function only affects web processes that have not already been
1619  * created. The best time to call it is when handling
1620  * #WebKitWebContext::initialize-notification-permissions so as to
1621  * ensure that new web processes receive the most recent set of
1622  * permissions.
1623  *
1624  * Since: 2.16
1625  */
1626 void webkit_web_context_initialize_notification_permissions(WebKitWebContext* context, GList* allowedOrigins, GList* disallowedOrigins)
1627 {
1628     HashMap<String, bool> map;
1629     g_list_foreach(allowedOrigins, [](gpointer data, gpointer userData) {
1630         addOriginToMap(static_cast<WebKitSecurityOrigin*>(data), static_cast<HashMap<String, bool>*>(userData), true);
1631     }, &map);
1632     g_list_foreach(disallowedOrigins, [](gpointer data, gpointer userData) {
1633         addOriginToMap(static_cast<WebKitSecurityOrigin*>(data), static_cast<HashMap<String, bool>*>(userData), false);
1634     }, &map);
1635     context->priv->notificationProvider->setNotificationPermissions(WTFMove(map));
1636 }
1637
1638 void webkitWebContextInitializeNotificationPermissions(WebKitWebContext* context)
1639 {
1640     g_signal_emit(context, signals[INITIALIZE_NOTIFICATION_PERMISSIONS], 0);
1641 }
1642
1643 WebKitDownload* webkitWebContextGetOrCreateDownload(DownloadProxy* downloadProxy)
1644 {
1645     GRefPtr<WebKitDownload> download = downloadsMap().get(downloadProxy);
1646     if (download)
1647         return download.get();
1648
1649     download = adoptGRef(webkitDownloadCreate(downloadProxy));
1650     downloadsMap().set(downloadProxy, download.get());
1651     return download.get();
1652 }
1653
1654 WebKitDownload* webkitWebContextStartDownload(WebKitWebContext* context, const char* uri, WebPageProxy* initiatingPage)
1655 {
1656     WebCore::ResourceRequest request(String::fromUTF8(uri));
1657     return webkitWebContextGetOrCreateDownload(&context->priv->processPool->download(WebKit::WebsiteDataStore::defaultDataStore().get(), initiatingPage, request));
1658 }
1659
1660 void webkitWebContextRemoveDownload(DownloadProxy* downloadProxy)
1661 {
1662     downloadsMap().remove(downloadProxy);
1663 }
1664
1665 void webkitWebContextDownloadStarted(WebKitWebContext* context, WebKitDownload* download)
1666 {
1667     g_signal_emit(context, signals[DOWNLOAD_STARTED], 0, download);
1668 }
1669
1670 GVariant* webkitWebContextInitializeWebExtensions(WebKitWebContext* context)
1671 {
1672     g_signal_emit(context, signals[INITIALIZE_WEB_EXTENSIONS], 0);
1673     return g_variant_new("(msmv)",
1674         context->priv->webExtensionsDirectory.data(),
1675         context->priv->webExtensionsInitializationUserData.get());
1676 }
1677
1678 WebProcessPool& webkitWebContextGetProcessPool(WebKitWebContext* context)
1679 {
1680     g_assert(WEBKIT_IS_WEB_CONTEXT(context));
1681
1682     return *context->priv->processPool;
1683 }
1684
1685 void webkitWebContextCreatePageForWebView(WebKitWebContext* context, WebKitWebView* webView, WebKitUserContentManager* userContentManager, WebKitWebView* relatedView)
1686 {
1687     auto pageConfiguration = API::PageConfiguration::create();
1688     pageConfiguration->setProcessPool(context->priv->processPool.get());
1689     pageConfiguration->setPreferences(webkitSettingsGetPreferences(webkit_web_view_get_settings(webView)));
1690     pageConfiguration->setRelatedPage(relatedView ? &webkitWebViewGetPage(relatedView) : nullptr);
1691     pageConfiguration->setUserContentController(userContentManager ? webkitUserContentManagerGetUserContentControllerProxy(userContentManager) : nullptr);
1692     pageConfiguration->setControlledByAutomation(webkit_web_view_is_controlled_by_automation(webView));
1693
1694     WebKitWebsiteDataManager* manager = webkitWebViewGetWebsiteDataManager(webView);
1695     if (!manager)
1696         manager = context->priv->websiteDataManager.get();
1697     pageConfiguration->setWebsiteDataStore(&webkitWebsiteDataManagerGetDataStore(manager));
1698     webkitWebViewCreatePage(webView, WTFMove(pageConfiguration));
1699
1700     auto& page = webkitWebViewGetPage(webView);
1701     for (auto& it : context->priv->uriSchemeHandlers) {
1702         Ref<WebURLSchemeHandler> handler(*it.value);
1703         page.setURLSchemeHandlerForScheme(WTFMove(handler), it.key);
1704     }
1705
1706     context->priv->webViews.set(webkit_web_view_get_page_id(webView), webView);
1707 }
1708
1709 void webkitWebContextWebViewDestroyed(WebKitWebContext* context, WebKitWebView* webView)
1710 {
1711     context->priv->webViews.remove(webkit_web_view_get_page_id(webView));
1712 }
1713
1714 WebKitWebView* webkitWebContextGetWebViewForPage(WebKitWebContext* context, WebPageProxy* page)
1715 {
1716     return page ? context->priv->webViews.get(page->webPageID().toUInt64()) : nullptr;
1717 }