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