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