[GTK] Implement custom URI schemes with CustomProtocols
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / gtk / 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 "APIString.h"
24 #include "WebBatteryManagerProxy.h"
25 #include "WebCertificateInfo.h"
26 #include "WebCookieManagerProxy.h"
27 #include "WebGeolocationManagerProxy.h"
28 #include "WebKitBatteryProvider.h"
29 #include "WebKitCertificateInfoPrivate.h"
30 #include "WebKitCookieManagerPrivate.h"
31 #include "WebKitDownloadClient.h"
32 #include "WebKitDownloadPrivate.h"
33 #include "WebKitFaviconDatabasePrivate.h"
34 #include "WebKitGeolocationProvider.h"
35 #include "WebKitInjectedBundleClient.h"
36 #include "WebKitPluginPrivate.h"
37 #include "WebKitPrivate.h"
38 #include "WebKitRequestManagerClient.h"
39 #include "WebKitSecurityManagerPrivate.h"
40 #include "WebKitTextChecker.h"
41 #include "WebKitURISchemeRequestPrivate.h"
42 #include "WebKitWebContextPrivate.h"
43 #include "WebKitWebViewBasePrivate.h"
44 #include "WebKitWebViewGroupPrivate.h"
45 #include "WebResourceCacheManagerProxy.h"
46 #include <WebCore/FileSystem.h>
47 #include <WebCore/IconDatabase.h>
48 #include <WebCore/Language.h>
49 #include <wtf/HashMap.h>
50 #include <wtf/OwnPtr.h>
51 #include <wtf/PassRefPtr.h>
52 #include <wtf/RefCounted.h>
53 #include <wtf/gobject/GRefPtr.h>
54 #include <wtf/gobject/GUniquePtr.h>
55 #include <wtf/text/CString.h>
56
57 using namespace WebKit;
58
59 /**
60  * SECTION: WebKitWebContext
61  * @Short_description: Manages aspects common to all #WebKitWebView<!-- -->s
62  * @Title: WebKitWebContext
63  *
64  * The #WebKitWebContext manages all aspects common to all
65  * #WebKitWebView<!-- -->s.
66  *
67  * You can define the #WebKitCacheModel with
68  * webkit_web_context_set_cache_model(), depending on the needs of
69  * your application. You can access the #WebKitCookieManager or the
70  * #WebKitSecurityManager to specify the behaviour of your application
71  * regarding cookies and security, using
72  * webkit_web_context_get_cookie_manager() and
73  * webkit_web_context_get_security_manager() for that.
74  *
75  * It is also possible to change your preferred language or enable
76  * spell checking, using webkit_web_context_set_preferred_languages(),
77  * webkit_web_context_set_spell_checking_languages() and
78  * webkit_web_context_set_spell_checking_enabled().
79  *
80  * You can use webkit_web_context_register_uri_scheme() to register
81  * custom URI schemes, and manage several other settings.
82  *
83  */
84
85 enum {
86     DOWNLOAD_STARTED,
87     INITIALIZE_WEB_EXTENSIONS,
88
89     LAST_SIGNAL
90 };
91
92 class WebKitURISchemeHandler: public RefCounted<WebKitURISchemeHandler> {
93 public:
94     WebKitURISchemeHandler()
95         : m_callback(0)
96         , m_userData(0)
97         , m_destroyNotify(0)
98     {
99     }
100     WebKitURISchemeHandler(WebKitURISchemeRequestCallback callback, void* userData, GDestroyNotify destroyNotify)
101         : m_callback(callback)
102         , m_userData(userData)
103         , m_destroyNotify(destroyNotify)
104     {
105     }
106
107     ~WebKitURISchemeHandler()
108     {
109         if (m_destroyNotify)
110             m_destroyNotify(m_userData);
111     }
112
113     bool hasCallback()
114     {
115         return m_callback;
116     }
117
118     void performCallback(WebKitURISchemeRequest* request)
119     {
120         ASSERT(m_callback);
121
122         m_callback(request, m_userData);
123     }
124
125 private:
126     WebKitURISchemeRequestCallback m_callback;
127     void* m_userData;
128     GDestroyNotify m_destroyNotify;
129 };
130
131 typedef HashMap<String, RefPtr<WebKitURISchemeHandler> > URISchemeHandlerMap;
132 typedef HashMap<uint64_t, GRefPtr<WebKitURISchemeRequest> > URISchemeRequestMap;
133
134 struct _WebKitWebContextPrivate {
135     RefPtr<WebContext> context;
136
137     GRefPtr<WebKitCookieManager> cookieManager;
138     GRefPtr<WebKitFaviconDatabase> faviconDatabase;
139     GRefPtr<WebKitSecurityManager> securityManager;
140     RefPtr<WebSoupCustomProtocolRequestManager> requestManager;
141     URISchemeHandlerMap uriSchemeHandlers;
142     URISchemeRequestMap uriSchemeRequests;
143 #if ENABLE(GEOLOCATION)
144     RefPtr<WebKitGeolocationProvider> geolocationProvider;
145 #endif
146 #if ENABLE(BATTERY_STATUS)
147     RefPtr<WebKitBatteryProvider> batteryProvider;
148 #endif
149 #if ENABLE(SPELLCHECK)
150     OwnPtr<WebKitTextChecker> textChecker;
151 #endif
152     CString faviconDatabaseDirectory;
153     WebKitTLSErrorsPolicy tlsErrorsPolicy;
154
155     HashMap<uint64_t, WebKitWebView*> webViews;
156     GRefPtr<WebKitWebViewGroup> defaultWebViewGroup;
157
158     CString webExtensionsDirectory;
159     GRefPtr<GVariant> webExtensionsInitializationUserData;
160 };
161
162 static guint signals[LAST_SIGNAL] = { 0, };
163
164 WEBKIT_DEFINE_TYPE(WebKitWebContext, webkit_web_context, G_TYPE_OBJECT)
165
166 static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass)
167 {
168     GObjectClass* gObjectClass = G_OBJECT_CLASS(webContextClass);
169
170     /**
171      * WebKitWebContext::download-started:
172      * @context: the #WebKitWebContext
173      * @download: the #WebKitDownload associated with this event
174      *
175      * This signal is emitted when a new download request is made.
176      */
177     signals[DOWNLOAD_STARTED] =
178         g_signal_new("download-started",
179                      G_TYPE_FROM_CLASS(gObjectClass),
180                      G_SIGNAL_RUN_LAST,
181                      0, 0, 0,
182                      g_cclosure_marshal_VOID__OBJECT,
183                      G_TYPE_NONE, 1,
184                      WEBKIT_TYPE_DOWNLOAD);
185
186     /**
187      * WebKitWebContext::initialize-web-extensions:
188      * @context: the #WebKitWebContext
189      *
190      * This signal is emitted when a new web process is about to be
191      * launched. It signals the most appropriate moment to use
192      * webkit_web_context_set_web_extensions_initialization_user_data()
193      * and webkit_web_context_set_web_extensions_directory().
194      *
195      * Since: 2.4
196      */
197     signals[INITIALIZE_WEB_EXTENSIONS] =
198         g_signal_new("initialize-web-extensions",
199             G_TYPE_FROM_CLASS(gObjectClass),
200             G_SIGNAL_RUN_LAST,
201             0, nullptr, nullptr,
202             g_cclosure_marshal_VOID__VOID,
203             G_TYPE_NONE, 0);
204 }
205
206 static CString injectedBundleDirectory()
207 {
208     const char* bundleDirectory = g_getenv("WEBKIT_INJECTED_BUNDLE_PATH");
209     if (bundleDirectory && g_file_test(bundleDirectory, G_FILE_TEST_IS_DIR))
210         return bundleDirectory;
211
212     static const char* injectedBundlePath = LIBDIR G_DIR_SEPARATOR_S "webkit2gtk-" WEBKITGTK_API_VERSION_STRING
213         G_DIR_SEPARATOR_S "injected-bundle" G_DIR_SEPARATOR_S;
214     return injectedBundlePath;
215 }
216
217 static CString injectedBundleFilename()
218 {
219     GUniquePtr<char> bundleFilename(g_build_filename(injectedBundleDirectory().data(), "libwebkit2gtkinjectedbundle.so", NULL));
220     return bundleFilename.get();
221 }
222
223 static gpointer createDefaultWebContext(gpointer)
224 {
225     static GRefPtr<WebKitWebContext> webContext = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, NULL)));
226     WebKitWebContextPrivate* priv = webContext->priv;
227
228     priv->context = WebContext::create(WebCore::filenameToString(injectedBundleFilename().data()));
229     priv->requestManager = webContext->priv->context->supplement<WebSoupCustomProtocolRequestManager>();
230     priv->context->setCacheModel(CacheModelPrimaryWebBrowser);
231 #if ENABLE(NETWORK_PROCESS)
232     // FIXME: Temporary use an env var until we have API to set the process model. See https://bugs.webkit.org/show_bug.cgi?id=125463.
233     priv->context->setUsesNetworkProcess(g_getenv("WEBKIT_USE_NETWORK_PROCESS"));
234 #endif
235     priv->tlsErrorsPolicy = WEBKIT_TLS_ERRORS_POLICY_IGNORE;
236
237     attachInjectedBundleClientToContext(webContext.get());
238     attachDownloadClientToContext(webContext.get());
239     attachRequestManagerClientToContext(webContext.get());
240
241 #if ENABLE(GEOLOCATION)
242     priv->geolocationProvider = WebKitGeolocationProvider::create(priv->context->supplement<WebGeolocationManagerProxy>());
243 #endif
244 #if ENABLE(BATTERY_STATUS)
245     priv->batteryProvider = WebKitBatteryProvider::create(priv->context->supplement<WebBatteryManagerProxy>());
246 #endif
247 #if ENABLE(SPELLCHECK)
248     priv->textChecker = WebKitTextChecker::create();
249 #endif
250     return webContext.get();
251 }
252
253 /**
254  * webkit_web_context_get_default:
255  *
256  * Gets the default web context
257  *
258  * Returns: (transfer none): a #WebKitWebContext
259  */
260 WebKitWebContext* webkit_web_context_get_default(void)
261 {
262     static GOnce onceInit = G_ONCE_INIT;
263     return WEBKIT_WEB_CONTEXT(g_once(&onceInit, createDefaultWebContext, 0));
264 }
265
266 /**
267  * webkit_web_context_set_cache_model:
268  * @context: the #WebKitWebContext
269  * @cache_model: a #WebKitCacheModel
270  *
271  * Specifies a usage model for WebViews, which WebKit will use to
272  * determine its caching behavior. All web views follow the cache
273  * model. This cache model determines the RAM and disk space to use
274  * for caching previously viewed content .
275  *
276  * Research indicates that users tend to browse within clusters of
277  * documents that hold resources in common, and to revisit previously
278  * visited documents. WebKit and the frameworks below it include
279  * built-in caches that take advantage of these patterns,
280  * substantially improving document load speed in browsing
281  * situations. The WebKit cache model controls the behaviors of all of
282  * these caches, including various WebCore caches.
283  *
284  * Browsers can improve document load speed substantially by
285  * specifying %WEBKIT_CACHE_MODEL_WEB_BROWSER. Applications without a
286  * browsing interface can reduce memory usage substantially by
287  * specifying %WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER. The default value is
288  * %WEBKIT_CACHE_MODEL_WEB_BROWSER.
289  */
290 void webkit_web_context_set_cache_model(WebKitWebContext* context, WebKitCacheModel model)
291 {
292     CacheModel cacheModel;
293
294     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
295
296     switch (model) {
297     case WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER:
298         cacheModel = CacheModelDocumentViewer;
299         break;
300     case WEBKIT_CACHE_MODEL_WEB_BROWSER:
301         cacheModel = CacheModelPrimaryWebBrowser;
302         break;
303     case WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER:
304         cacheModel = CacheModelDocumentBrowser;
305         break;
306     default:
307         g_assert_not_reached();
308     }
309
310     if (cacheModel != context->priv->context->cacheModel())
311         context->priv->context->setCacheModel(cacheModel);
312 }
313
314 /**
315  * webkit_web_context_get_cache_model:
316  * @context: the #WebKitWebContext
317  *
318  * Returns the current cache model. For more information about this
319  * value check the documentation of the function
320  * webkit_web_context_set_cache_model().
321  *
322  * Returns: the current #WebKitCacheModel
323  */
324 WebKitCacheModel webkit_web_context_get_cache_model(WebKitWebContext* context)
325 {
326     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_CACHE_MODEL_WEB_BROWSER);
327
328     switch (context->priv->context->cacheModel()) {
329     case CacheModelDocumentViewer:
330         return WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER;
331     case CacheModelPrimaryWebBrowser:
332         return WEBKIT_CACHE_MODEL_WEB_BROWSER;
333     case CacheModelDocumentBrowser:
334         return WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER;
335     default:
336         g_assert_not_reached();
337     }
338
339     return WEBKIT_CACHE_MODEL_WEB_BROWSER;
340 }
341
342 /**
343  * webkit_web_context_clear_cache:
344  * @context: a #WebKitWebContext
345  *
346  * Clears all resources currently cached.
347  * See also webkit_web_context_set_cache_model().
348  */
349 void webkit_web_context_clear_cache(WebKitWebContext* context)
350 {
351     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
352
353     context->priv->context->supplement<WebResourceCacheManagerProxy>()->clearCacheForAllOrigins(AllResourceCaches);
354 }
355
356 typedef HashMap<DownloadProxy*, GRefPtr<WebKitDownload> > DownloadsMap;
357
358 static DownloadsMap& downloadsMap()
359 {
360     DEFINE_STATIC_LOCAL(DownloadsMap, downloads, ());
361     return downloads;
362 }
363
364 /**
365  * webkit_web_context_download_uri:
366  * @context: a #WebKitWebContext
367  * @uri: the URI to download
368  *
369  * Requests downloading of the specified URI string. The download operation
370  * will not be associated to any #WebKitWebView, if you are interested in
371  * starting a download from a particular #WebKitWebView use
372  * webkit_web_view_download_uri() instead.
373  *
374  * Returns: (transfer full): a new #WebKitDownload representing the
375  *    the download operation.
376  */
377 WebKitDownload* webkit_web_context_download_uri(WebKitWebContext* context, const gchar* uri)
378 {
379     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
380     g_return_val_if_fail(uri, 0);
381
382     return webkitWebContextStartDownload(context, uri, 0);
383 }
384
385 /**
386  * webkit_web_context_get_cookie_manager:
387  * @context: a #WebKitWebContext
388  *
389  * Get the #WebKitCookieManager of @context.
390  *
391  * Returns: (transfer none): the #WebKitCookieManager of @context.
392  */
393 WebKitCookieManager* webkit_web_context_get_cookie_manager(WebKitWebContext* context)
394 {
395     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
396
397     WebKitWebContextPrivate* priv = context->priv;
398     if (!priv->cookieManager)
399         priv->cookieManager = adoptGRef(webkitCookieManagerCreate(priv->context->supplement<WebCookieManagerProxy>()));
400
401     return priv->cookieManager.get();
402 }
403
404 static void ensureFaviconDatabase(WebKitWebContext* context)
405 {
406     WebKitWebContextPrivate* priv = context->priv;
407     if (priv->faviconDatabase)
408         return;
409
410     priv->faviconDatabase = adoptGRef(webkitFaviconDatabaseCreate(priv->context->iconDatabase()));
411 }
412
413 /**
414  * webkit_web_context_set_favicon_database_directory:
415  * @context: a #WebKitWebContext
416  * @path: (allow-none): an absolute path to the icon database
417  * directory or %NULL to use the defaults
418  *
419  * Set the directory path to be used to store the favicons database
420  * for @context on disk. Passing %NULL as @path means using the
421  * default directory for the platform (see g_get_user_data_dir()).
422  *
423  * Calling this method also means enabling the favicons database for
424  * its use from the applications, so that's why it's expected to be
425  * called only once. Further calls for the same instance of
426  * #WebKitWebContext won't cause any effect.
427  */
428 void webkit_web_context_set_favicon_database_directory(WebKitWebContext* context, const gchar* path)
429 {
430     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
431
432     WebKitWebContextPrivate* priv = context->priv;
433     WebIconDatabase* iconDatabase = priv->context->iconDatabase();
434     if (iconDatabase->isOpen())
435         return;
436
437     ensureFaviconDatabase(context);
438
439     // Use default if 0 is passed as parameter.
440     String directoryPath = WebCore::filenameToString(path);
441     priv->faviconDatabaseDirectory = directoryPath.isEmpty()
442         ? priv->context->iconDatabasePath().utf8()
443         : directoryPath.utf8();
444
445     // Build the full path to the icon database file on disk.
446     GUniquePtr<gchar> faviconDatabasePath(g_build_filename(priv->faviconDatabaseDirectory.data(),
447         WebCore::IconDatabase::defaultDatabaseFilename().utf8().data(), nullptr));
448
449     // Setting the path will cause the icon database to be opened.
450     priv->context->setIconDatabasePath(WebCore::filenameToString(faviconDatabasePath.get()));
451 }
452
453 /**
454  * webkit_web_context_get_favicon_database_directory:
455  * @context: a #WebKitWebContext
456  *
457  * Get the directory path being used to store the favicons database
458  * for @context, or %NULL if
459  * webkit_web_context_set_favicon_database_directory() hasn't been
460  * called yet.
461  *
462  * This function will always return the same path after having called
463  * webkit_web_context_set_favicon_database_directory() for the first
464  * time.
465  *
466  * Returns: (transfer none): the path of the directory of the favicons
467  * database associated with @context, or %NULL.
468  */
469 const gchar* webkit_web_context_get_favicon_database_directory(WebKitWebContext *context)
470 {
471     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
472
473     WebKitWebContextPrivate* priv = context->priv;
474     if (priv->faviconDatabaseDirectory.isNull())
475         return 0;
476
477     return priv->faviconDatabaseDirectory.data();
478 }
479
480 /**
481  * webkit_web_context_get_favicon_database:
482  * @context: a #WebKitWebContext
483  *
484  * Get the #WebKitFaviconDatabase associated with @context.
485  *
486  * To initialize the database you need to call
487  * webkit_web_context_set_favicon_database_directory().
488  *
489  * Returns: (transfer none): the #WebKitFaviconDatabase of @context.
490  */
491 WebKitFaviconDatabase* webkit_web_context_get_favicon_database(WebKitWebContext* context)
492 {
493     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
494
495     ensureFaviconDatabase(context);
496     return context->priv->faviconDatabase.get();
497 }
498
499 /**
500  * webkit_web_context_get_security_manager:
501  * @context: a #WebKitWebContext
502  *
503  * Get the #WebKitSecurityManager of @context.
504  *
505  * Returns: (transfer none): the #WebKitSecurityManager of @context.
506  */
507 WebKitSecurityManager* webkit_web_context_get_security_manager(WebKitWebContext* context)
508 {
509     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
510
511     WebKitWebContextPrivate* priv = context->priv;
512     if (!priv->securityManager)
513         priv->securityManager = adoptGRef(webkitSecurityManagerCreate(context));
514
515     return priv->securityManager.get();
516 }
517
518 /**
519  * webkit_web_context_set_additional_plugins_directory:
520  * @context: a #WebKitWebContext
521  * @directory: the directory to add
522  *
523  * Set an additional directory where WebKit will look for plugins.
524  */
525 void webkit_web_context_set_additional_plugins_directory(WebKitWebContext* context, const char* directory)
526 {
527     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
528     g_return_if_fail(directory);
529
530     context->priv->context->setAdditionalPluginsDirectory(WebCore::filenameToString(directory));
531 }
532
533 static void destroyPluginList(GList* plugins)
534 {
535     g_list_free_full(plugins, g_object_unref);
536 }
537
538 static void webkitWebContextGetPluginThread(GTask* task, gpointer object, gpointer taskData, GCancellable*)
539 {
540     Vector<PluginModuleInfo> plugins = WEBKIT_WEB_CONTEXT(object)->priv->context->pluginInfoStore().plugins();
541     GList* returnValue = 0;
542     for (size_t i = 0; i < plugins.size(); ++i)
543         returnValue = g_list_prepend(returnValue, webkitPluginCreate(plugins[i]));
544     g_task_return_pointer(task, returnValue, reinterpret_cast<GDestroyNotify>(destroyPluginList));
545 }
546
547 /**
548  * webkit_web_context_get_plugins:
549  * @context: a #WebKitWebContext
550  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
551  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
552  * @user_data: (closure): the data to pass to callback function
553  *
554  * Asynchronously get the list of installed plugins.
555  *
556  * When the operation is finished, @callback will be called. You can then call
557  * webkit_web_context_get_plugins_finish() to get the result of the operation.
558  */
559 void webkit_web_context_get_plugins(WebKitWebContext* context, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
560 {
561     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
562
563     GRefPtr<GTask> task = adoptGRef(g_task_new(context, cancellable, callback, userData));
564     g_task_run_in_thread(task.get(), webkitWebContextGetPluginThread);
565 }
566
567 /**
568  * webkit_web_context_get_plugins_finish:
569  * @context: a #WebKitWebContext
570  * @result: a #GAsyncResult
571  * @error: return location for error or %NULL to ignore
572  *
573  * Finish an asynchronous operation started with webkit_web_context_get_plugins.
574  *
575  * Returns: (element-type WebKitPlugin) (transfer full): a #GList of #WebKitPlugin. You must free the #GList with
576  *    g_list_free() and unref the #WebKitPlugin<!-- -->s with g_object_unref() when you're done with them.
577  */
578 GList* webkit_web_context_get_plugins_finish(WebKitWebContext* context, GAsyncResult* result, GError** error)
579 {
580     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
581     g_return_val_if_fail(g_task_is_valid(result, context), 0);
582
583     return static_cast<GList*>(g_task_propagate_pointer(G_TASK(result), error));
584 }
585
586 /**
587  * webkit_web_context_register_uri_scheme:
588  * @context: a #WebKitWebContext
589  * @scheme: the network scheme to register
590  * @callback: (scope async): a #WebKitURISchemeRequestCallback
591  * @user_data: data to pass to callback function
592  * @user_data_destroy_func: destroy notify for @user_data
593  *
594  * Register @scheme in @context, so that when an URI request with @scheme is made in the
595  * #WebKitWebContext, the #WebKitURISchemeRequestCallback registered will be called with a
596  * #WebKitURISchemeRequest.
597  * It is possible to handle URI scheme requests asynchronously, by calling g_object_ref() on the
598  * #WebKitURISchemeRequest and calling webkit_uri_scheme_request_finish() later
599  * when the data of the request is available or
600  * webkit_uri_scheme_request_finish_error() in case of error.
601  *
602  * <informalexample><programlisting>
603  * static void
604  * about_uri_scheme_request_cb (WebKitURISchemeRequest *request,
605  *                              gpointer                user_data)
606  * {
607  *     GInputStream *stream;
608  *     gsize         stream_length;
609  *     const gchar  *path;
610  *
611  *     path = webkit_uri_scheme_request_get_path (request);
612  *     if (!g_strcmp0 (path, "plugins")) {
613  *         /<!-- -->* Create a GInputStream with the contents of plugins about page, and set its length to stream_length *<!-- -->/
614  *     } else if (!g_strcmp0 (path, "memory")) {
615  *         /<!-- -->* Create a GInputStream with the contents of memory about page, and set its length to stream_length *<!-- -->/
616  *     } else if (!g_strcmp0 (path, "applications")) {
617  *         /<!-- -->* Create a GInputStream with the contents of applications about page, and set its length to stream_length *<!-- -->/
618  *     } else if (!g_strcmp0 (path, "example")) {
619  *         gchar *contents;
620  *
621  *         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;");
622  *         stream_length = strlen (contents);
623  *         stream = g_memory_input_stream_new_from_data (contents, stream_length, g_free);
624  *     } else {
625  *         GError *error;
626  *
627  *         error = g_error_new (ABOUT_HANDLER_ERROR, ABOUT_HANDLER_ERROR_INVALID, "Invalid about:%s page.", path);
628  *         webkit_uri_scheme_request_finish_error (request, error);
629  *         g_error_free (error);
630  *         return;
631  *     }
632  *     webkit_uri_scheme_request_finish (request, stream, stream_length, "text/html");
633  *     g_object_unref (stream);
634  * }
635  * </programlisting></informalexample>
636  */
637 void webkit_web_context_register_uri_scheme(WebKitWebContext* context, const char* scheme, WebKitURISchemeRequestCallback callback, gpointer userData, GDestroyNotify destroyNotify)
638 {
639     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
640     g_return_if_fail(scheme);
641     g_return_if_fail(callback);
642
643     RefPtr<WebKitURISchemeHandler> handler = adoptRef(new WebKitURISchemeHandler(callback, userData, destroyNotify));
644     context->priv->uriSchemeHandlers.set(String::fromUTF8(scheme), handler.get());
645     context->priv->requestManager->registerSchemeForCustomProtocol(String::fromUTF8(scheme));
646 }
647
648 /**
649  * webkit_web_context_get_spell_checking_enabled:
650  * @context: a #WebKitWebContext
651  *
652  * Get whether spell checking feature is currently enabled.
653  *
654  * Returns: %TRUE If spell checking is enabled, or %FALSE otherwise.
655  */
656 gboolean webkit_web_context_get_spell_checking_enabled(WebKitWebContext* context)
657 {
658     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
659
660 #if ENABLE(SPELLCHECK)
661     return context->priv->textChecker->isSpellCheckingEnabled();
662 #else
663     return false;
664 #endif
665 }
666
667 /**
668  * webkit_web_context_set_spell_checking_enabled:
669  * @context: a #WebKitWebContext
670  * @enabled: Value to be set
671  *
672  * Enable or disable the spell checking feature.
673  */
674 void webkit_web_context_set_spell_checking_enabled(WebKitWebContext* context, gboolean enabled)
675 {
676     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
677
678 #if ENABLE(SPELLCHECK)
679     context->priv->textChecker->setSpellCheckingEnabled(enabled);
680 #endif
681 }
682
683 /**
684  * webkit_web_context_get_spell_checking_languages:
685  * @context: a #WebKitWebContext
686  *
687  * Get the the list of spell checking languages associated with
688  * @context, or %NULL if no languages have been previously set.
689  *
690  * See webkit_web_context_set_spell_checking_languages() for more
691  * details on the format of the languages in the list.
692  *
693  * Returns: (array zero-terminated=1) (element-type utf8) (transfer none): A %NULL-terminated
694  *    array of languages if available, or %NULL otherwise.
695  */
696 const gchar* const* webkit_web_context_get_spell_checking_languages(WebKitWebContext* context)
697 {
698     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
699
700 #if ENABLE(SPELLCHECK)
701     return context->priv->textChecker->getSpellCheckingLanguages();
702 #else
703     return 0;
704 #endif
705 }
706
707 /**
708  * webkit_web_context_set_spell_checking_languages:
709  * @context: a #WebKitWebContext
710  * @languages: (array zero-terminated=1) (transfer none): a %NULL-terminated list of spell checking languages
711  *
712  * Set the list of spell checking languages to be used for spell
713  * checking.
714  *
715  * The locale string typically is in the form lang_COUNTRY, where lang
716  * is an ISO-639 language code, and COUNTRY is an ISO-3166 country code.
717  * For instance, sv_FI for Swedish as written in Finland or pt_BR
718  * for Portuguese as written in Brazil.
719  *
720  * You need to call this function with a valid list of languages at
721  * least once in order to properly enable the spell checking feature
722  * in WebKit.
723  */
724 void webkit_web_context_set_spell_checking_languages(WebKitWebContext* context, const gchar* const* languages)
725 {
726     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
727     g_return_if_fail(languages);
728
729 #if ENABLE(SPELLCHECK)
730     context->priv->textChecker->setSpellCheckingLanguages(languages);
731 #endif
732 }
733
734 /**
735  * webkit_web_context_set_preferred_languages:
736  * @context: a #WebKitWebContext
737  * @languages: (allow-none) (array zero-terminated=1) (element-type utf8) (transfer none): a %NULL-terminated list of language identifiers
738  *
739  * Set the list of preferred languages, sorted from most desirable
740  * to least desirable. The list will be used to build the "Accept-Language"
741  * header that will be included in the network requests started by
742  * the #WebKitWebContext.
743  */
744 void webkit_web_context_set_preferred_languages(WebKitWebContext* context, const gchar* const* languageList)
745 {
746     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
747
748     if (!languageList || !g_strv_length(const_cast<char**>(languageList)))
749         return;
750
751     Vector<String> languages;
752     for (size_t i = 0; languageList[i]; ++i)
753         languages.append(String::fromUTF8(languageList[i]).lower().replace("_", "-"));
754
755     WebCore::overrideUserPreferredLanguages(languages);
756     WebCore::languageDidChange();
757 }
758
759 /**
760  * webkit_web_context_set_tls_errors_policy:
761  * @context: a #WebKitWebContext
762  * @policy: a #WebKitTLSErrorsPolicy
763  *
764  * Set the TLS errors policy of @context as @policy
765  */
766 void webkit_web_context_set_tls_errors_policy(WebKitWebContext* context, WebKitTLSErrorsPolicy policy)
767 {
768     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
769
770     if (context->priv->tlsErrorsPolicy == policy)
771         return;
772
773     context->priv->tlsErrorsPolicy = policy;
774     bool ignoreTLSErrors = policy == WEBKIT_TLS_ERRORS_POLICY_IGNORE;
775     if (context->priv->context->ignoreTLSErrors() != ignoreTLSErrors)
776         context->priv->context->setIgnoreTLSErrors(ignoreTLSErrors);
777 }
778
779 /**
780  * webkit_web_context_get_tls_errors_policy:
781  * @context: a #WebKitWebContext
782  *
783  * Get the TLS errors policy of @context
784  *
785  * Returns: a #WebKitTLSErrorsPolicy
786  */
787 WebKitTLSErrorsPolicy webkit_web_context_get_tls_errors_policy(WebKitWebContext* context)
788 {
789     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_TLS_ERRORS_POLICY_IGNORE);
790
791     return context->priv->tlsErrorsPolicy;
792 }
793
794 /**
795  * webkit_web_context_set_web_extensions_directory:
796  * @context: a #WebKitWebContext
797  * @directory: the directory to add
798  *
799  * Set the directory where WebKit will look for Web Extensions.
800  * This method must be called before loading anything in this context,
801  * otherwise it will not have any effect. You can connect to
802  * #WebKitWebContext::initialize-web-extensions to call this method
803  * before anything is loaded.
804  */
805 void webkit_web_context_set_web_extensions_directory(WebKitWebContext* context, const char* directory)
806 {
807     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
808     g_return_if_fail(directory);
809
810     context->priv->webExtensionsDirectory = directory;
811 }
812
813 /**
814  * webkit_web_context_set_web_extensions_initialization_user_data:
815  * @context: a #WebKitWebContext
816  * @user_data: a #GVariant
817  *
818  * Set user data to be passed to Web Extensions on initialization.
819  * The data will be passed to the
820  * #WebKitWebExtensionInitializeWithUserDataFunction.
821  * This method must be called before loading anything in this context,
822  * otherwise it will not have any effect. You can connect to
823  * #WebKitWebContext::initialize-web-extensions to call this method
824  * before anything is loaded.
825  *
826  * Since: 2.4
827  */
828 void webkit_web_context_set_web_extensions_initialization_user_data(WebKitWebContext* context, GVariant* userData)
829 {
830     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
831     g_return_if_fail(userData);
832
833     context->priv->webExtensionsInitializationUserData = userData;
834 }
835
836 /**
837  * webkit_web_context_set_disk_cache_directory:
838  * @context: a #WebKitWebContext
839  * @directory: the directory to set
840  *
841  * Set the directory where disk cache files will be stored
842  * This method must be called before loading anything in this context, otherwise
843  * it will not have any effect.
844  */
845 void webkit_web_context_set_disk_cache_directory(WebKitWebContext* context, const char* directory)
846 {
847     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
848     g_return_if_fail(directory);
849
850     context->priv->context->setDiskCacheDirectory(WebCore::filenameToString(directory));
851 }
852
853 /**
854  * webkit_web_context_prefetch_dns:
855  * @context: a #WebKitWebContext
856  * @hostname: a hostname to be resolved
857  *
858  * Resolve the domain name of the given @hostname in advance, so that if a URI
859  * of @hostname is requested the load will be performed more quickly.
860  */
861 void webkit_web_context_prefetch_dns(WebKitWebContext* context, const char* hostname)
862 {
863     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
864     g_return_if_fail(hostname);
865
866     ImmutableDictionary::MapType message;
867     message.set(String::fromUTF8("Hostname"), API::String::create(String::fromUTF8(hostname)));
868     context->priv->context->postMessageToInjectedBundle(String::fromUTF8("PrefetchDNS"), ImmutableDictionary::create(std::move(message)).get());
869 }
870
871 /**
872  * webkit_web_context_allow_tls_certificate_for_host:
873  * @context: a #WebKitWebContext
874  * @info: a #WebKitCertificateInfo
875  * @host: the host for which a certificate is to be allowed
876  *
877  * Ignore further TLS errors on the @host for the certificate present in @info.
878  *
879  * Since: 2.4
880  */
881 void webkit_web_context_allow_tls_certificate_for_host(WebKitWebContext* context, WebKitCertificateInfo* info, const gchar* host)
882 {
883     g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
884     g_return_if_fail(info);
885     g_return_if_fail(host);
886
887     RefPtr<WebCertificateInfo> webCertificateInfo = WebCertificateInfo::create(webkitCertificateInfoGetCertificateInfo(info));
888     context->priv->context->allowSpecificHTTPSCertificateForHost(webCertificateInfo.get(), String::fromUTF8(host));
889 }
890
891 WebKitDownload* webkitWebContextGetOrCreateDownload(DownloadProxy* downloadProxy)
892 {
893     GRefPtr<WebKitDownload> download = downloadsMap().get(downloadProxy);
894     if (download)
895         return download.get();
896
897     download = adoptGRef(webkitDownloadCreate(downloadProxy));
898     downloadsMap().set(downloadProxy, download.get());
899     return download.get();
900 }
901
902 WebKitDownload* webkitWebContextStartDownload(WebKitWebContext* context, const char* uri, WebPageProxy* initiatingPage)
903 {
904     WebCore::ResourceRequest request(String::fromUTF8(uri));
905     DownloadProxy* downloadProxy = context->priv->context->download(initiatingPage, request);
906     WebKitDownload* download = webkitDownloadCreateForRequest(downloadProxy, request);
907     downloadsMap().set(downloadProxy, download);
908     return download;
909 }
910
911 void webkitWebContextRemoveDownload(DownloadProxy* downloadProxy)
912 {
913     downloadsMap().remove(downloadProxy);
914 }
915
916 void webkitWebContextDownloadStarted(WebKitWebContext* context, WebKitDownload* download)
917 {
918     g_signal_emit(context, signals[DOWNLOAD_STARTED], 0, download);
919 }
920
921 GVariant* webkitWebContextInitializeWebExtensions(WebKitWebContext* context)
922 {
923     g_signal_emit(context, signals[INITIALIZE_WEB_EXTENSIONS], 0);
924     return g_variant_new("(msmv)",
925         context->priv->webExtensionsDirectory.data(),
926         context->priv->webExtensionsInitializationUserData.get());
927 }
928
929 WebContext* webkitWebContextGetContext(WebKitWebContext* context)
930 {
931     g_assert(WEBKIT_IS_WEB_CONTEXT(context));
932
933     return context->priv->context.get();
934 }
935
936 WebSoupCustomProtocolRequestManager* webkitWebContextGetRequestManager(WebKitWebContext* context)
937 {
938     return context->priv->requestManager.get();
939 }
940
941 void webkitWebContextStartLoadingCustomProtocol(WebKitWebContext* context, uint64_t customProtocolID, API::URLRequest* urlRequest)
942 {
943     // FIXME: We need to figure out how to get the initiating page.
944     GRefPtr<WebKitURISchemeRequest> request = adoptGRef(webkitURISchemeRequestCreate(customProtocolID, context, urlRequest, nullptr));
945     String scheme(String::fromUTF8(webkit_uri_scheme_request_get_scheme(request.get())));
946     RefPtr<WebKitURISchemeHandler> handler = context->priv->uriSchemeHandlers.get(scheme);
947     ASSERT(handler.get());
948     if (!handler->hasCallback())
949         return;
950
951     context->priv->uriSchemeRequests.set(customProtocolID, request.get());
952     handler->performCallback(request.get());
953 }
954
955 void webkitWebContextStopLoadingCustomProtocol(WebKitWebContext* context, uint64_t customProtocolID)
956 {
957     GRefPtr<WebKitURISchemeRequest> request = context->priv->uriSchemeRequests.get(customProtocolID);
958     if (!request.get())
959         return;
960     webkitURISchemeRequestCancel(request.get());
961 }
962
963 void webkitWebContextDidFinishLoadingCustomProtocol(WebKitWebContext* context, uint64_t customProtocolID)
964 {
965     context->priv->uriSchemeRequests.remove(customProtocolID);
966 }
967
968 void webkitWebContextCreatePageForWebView(WebKitWebContext* context, WebKitWebView* webView, WebKitWebViewGroup* webViewGroup)
969 {
970     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
971     WebPageGroup* pageGroup = webViewGroup ? webkitWebViewGroupGetPageGroup(webViewGroup) : 0;
972     webkitWebViewBaseCreateWebPage(webViewBase, context->priv->context.get(), pageGroup);
973
974     WebPageProxy* page = webkitWebViewBaseGetPage(webViewBase);
975     context->priv->webViews.set(page->pageID(), webView);
976
977     if (!pageGroup && !context->priv->defaultWebViewGroup)
978         context->priv->defaultWebViewGroup = adoptGRef(webkitWebViewGroupCreate(&page->pageGroup()));
979 }
980
981 void webkitWebContextWebViewDestroyed(WebKitWebContext* context, WebKitWebView* webView)
982 {
983     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
984     context->priv->webViews.remove(page->pageID());
985 }
986
987 WebKitWebView* webkitWebContextGetWebViewForPage(WebKitWebContext* context, WebPageProxy* page)
988 {
989     return page ? context->priv->webViews.get(page->pageID()) : 0;
990 }
991
992 WebKitWebViewGroup* webkitWebContextGetDefaultWebViewGroup(WebKitWebContext* context)
993 {
994     return context->priv->defaultWebViewGroup.get();
995 }