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