WebKitWebContext.cpp [plain text]
#include "config.h"
#include "WebKitWebContext.h"
#include "WebCookieManagerProxy.h"
#include "WebGeolocationManagerProxy.h"
#include "WebKitCookieManagerPrivate.h"
#include "WebKitDownloadClient.h"
#include "WebKitDownloadPrivate.h"
#include "WebKitFaviconDatabasePrivate.h"
#include "WebKitGeolocationProvider.h"
#include "WebKitInjectedBundleClient.h"
#include "WebKitPluginPrivate.h"
#include "WebKitPrivate.h"
#include "WebKitRequestManagerClient.h"
#include "WebKitSecurityManagerPrivate.h"
#include "WebKitTextChecker.h"
#include "WebKitURISchemeRequestPrivate.h"
#include "WebKitWebContextPrivate.h"
#include "WebKitWebViewBasePrivate.h"
#include "WebKitWebViewGroupPrivate.h"
#include "WebResourceCacheManagerProxy.h"
#include <WebCore/FileSystem.h>
#include <WebCore/IconDatabase.h>
#include <WebCore/Language.h>
#include <wtf/HashMap.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/gobject/GOwnPtr.h>
#include <wtf/gobject/GRefPtr.h>
#include <wtf/text/CString.h>
using namespace WebKit;
enum {
DOWNLOAD_STARTED,
LAST_SIGNAL
};
class WebKitURISchemeHandler: public RefCounted<WebKitURISchemeHandler> {
public:
WebKitURISchemeHandler()
: m_callback(0)
, m_userData(0)
, m_destroyNotify(0)
{
}
WebKitURISchemeHandler(WebKitURISchemeRequestCallback callback, void* userData, GDestroyNotify destroyNotify)
: m_callback(callback)
, m_userData(userData)
, m_destroyNotify(destroyNotify)
{
}
~WebKitURISchemeHandler()
{
if (m_destroyNotify)
m_destroyNotify(m_userData);
}
bool hasCallback()
{
return m_callback;
}
void performCallback(WebKitURISchemeRequest* request)
{
ASSERT(m_callback);
m_callback(request, m_userData);
}
private:
WebKitURISchemeRequestCallback m_callback;
void* m_userData;
GDestroyNotify m_destroyNotify;
};
typedef HashMap<String, RefPtr<WebKitURISchemeHandler> > URISchemeHandlerMap;
typedef HashMap<uint64_t, GRefPtr<WebKitURISchemeRequest> > URISchemeRequestMap;
struct _WebKitWebContextPrivate {
RefPtr<WebContext> context;
GRefPtr<WebKitCookieManager> cookieManager;
GRefPtr<WebKitFaviconDatabase> faviconDatabase;
GRefPtr<WebKitSecurityManager> securityManager;
RefPtr<WebSoupRequestManagerProxy> requestManager;
URISchemeHandlerMap uriSchemeHandlers;
URISchemeRequestMap uriSchemeRequests;
#if ENABLE(GEOLOCATION)
RefPtr<WebKitGeolocationProvider> geolocationProvider;
#endif
#if ENABLE(SPELLCHECK)
OwnPtr<WebKitTextChecker> textChecker;
#endif
CString faviconDatabaseDirectory;
WebKitTLSErrorsPolicy tlsErrorsPolicy;
HashMap<uint64_t, WebKitWebView*> webViews;
GRefPtr<WebKitWebViewGroup> defaultWebViewGroup;
};
static guint signals[LAST_SIGNAL] = { 0, };
WEBKIT_DEFINE_TYPE(WebKitWebContext, webkit_web_context, G_TYPE_OBJECT)
static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass)
{
GObjectClass* gObjectClass = G_OBJECT_CLASS(webContextClass);
signals[DOWNLOAD_STARTED] =
g_signal_new("download-started",
G_TYPE_FROM_CLASS(gObjectClass),
G_SIGNAL_RUN_LAST,
0, 0, 0,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
WEBKIT_TYPE_DOWNLOAD);
}
static CString injectedBundleDirectory()
{
if (const char* bundleDirectory = g_getenv("WEBKIT_INJECTED_BUNDLE_PATH"))
return bundleDirectory;
static const char* injectedBundlePath = LIBDIR G_DIR_SEPARATOR_S "webkit2gtk-" WEBKITGTK_API_VERSION_STRING
G_DIR_SEPARATOR_S "injected-bundle" G_DIR_SEPARATOR_S;
return injectedBundlePath;
}
static CString injectedBundleFilename()
{
GOwnPtr<char> bundleFilename(g_build_filename(injectedBundleDirectory().data(), "libwebkit2gtkinjectedbundle.so", NULL));
return bundleFilename.get();
}
static gpointer createDefaultWebContext(gpointer)
{
static GRefPtr<WebKitWebContext> webContext = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, NULL)));
WebKitWebContextPrivate* priv = webContext->priv;
priv->context = WebContext::create(WebCore::filenameToString(injectedBundleFilename().data()));
priv->requestManager = webContext->priv->context->supplement<WebSoupRequestManagerProxy>();
priv->context->setCacheModel(CacheModelPrimaryWebBrowser);
priv->tlsErrorsPolicy = WEBKIT_TLS_ERRORS_POLICY_IGNORE;
attachInjectedBundleClientToContext(webContext.get());
attachDownloadClientToContext(webContext.get());
attachRequestManagerClientToContext(webContext.get());
#if ENABLE(GEOLOCATION)
priv->geolocationProvider = WebKitGeolocationProvider::create(priv->context->supplement<WebGeolocationManagerProxy>());
#endif
#if ENABLE(SPELLCHECK)
priv->textChecker = WebKitTextChecker::create();
#endif
return webContext.get();
}
WebKitWebContext* webkit_web_context_get_default(void)
{
static GOnce onceInit = G_ONCE_INIT;
return WEBKIT_WEB_CONTEXT(g_once(&onceInit, createDefaultWebContext, 0));
}
void webkit_web_context_set_cache_model(WebKitWebContext* context, WebKitCacheModel model)
{
CacheModel cacheModel;
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
switch (model) {
case WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER:
cacheModel = CacheModelDocumentViewer;
break;
case WEBKIT_CACHE_MODEL_WEB_BROWSER:
cacheModel = CacheModelPrimaryWebBrowser;
break;
case WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER:
cacheModel = CacheModelDocumentBrowser;
break;
default:
g_assert_not_reached();
}
if (cacheModel != context->priv->context->cacheModel())
context->priv->context->setCacheModel(cacheModel);
}
WebKitCacheModel webkit_web_context_get_cache_model(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_CACHE_MODEL_WEB_BROWSER);
switch (context->priv->context->cacheModel()) {
case CacheModelDocumentViewer:
return WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER;
case CacheModelPrimaryWebBrowser:
return WEBKIT_CACHE_MODEL_WEB_BROWSER;
case CacheModelDocumentBrowser:
return WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER;
default:
g_assert_not_reached();
}
return WEBKIT_CACHE_MODEL_WEB_BROWSER;
}
void webkit_web_context_clear_cache(WebKitWebContext* context)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
context->priv->context->supplement<WebResourceCacheManagerProxy>()->clearCacheForAllOrigins(AllResourceCaches);
}
typedef HashMap<DownloadProxy*, GRefPtr<WebKitDownload> > DownloadsMap;
static DownloadsMap& downloadsMap()
{
DEFINE_STATIC_LOCAL(DownloadsMap, downloads, ());
return downloads;
}
WebKitDownload* webkit_web_context_download_uri(WebKitWebContext* context, const gchar* uri)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
g_return_val_if_fail(uri, 0);
return webkitWebContextStartDownload(context, uri, 0);
}
WebKitCookieManager* webkit_web_context_get_cookie_manager(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
WebKitWebContextPrivate* priv = context->priv;
if (!priv->cookieManager)
priv->cookieManager = adoptGRef(webkitCookieManagerCreate(priv->context->supplement<WebCookieManagerProxy>()));
return priv->cookieManager.get();
}
static void ensureFaviconDatabase(WebKitWebContext* context)
{
WebKitWebContextPrivate* priv = context->priv;
if (priv->faviconDatabase)
return;
priv->faviconDatabase = adoptGRef(webkitFaviconDatabaseCreate(priv->context->iconDatabase()));
}
void webkit_web_context_set_favicon_database_directory(WebKitWebContext* context, const gchar* path)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
WebKitWebContextPrivate* priv = context->priv;
WebIconDatabase* iconDatabase = priv->context->iconDatabase();
if (iconDatabase->isOpen())
return;
ensureFaviconDatabase(context);
String directoryPath = WebCore::filenameToString(path);
priv->faviconDatabaseDirectory = directoryPath.isEmpty()
? priv->context->iconDatabasePath().utf8()
: directoryPath.utf8();
GOwnPtr<gchar> faviconDatabasePath(g_build_filename(priv->faviconDatabaseDirectory.data(),
WebCore::IconDatabase::defaultDatabaseFilename().utf8().data(),
NULL));
priv->context->setIconDatabasePath(WebCore::filenameToString(faviconDatabasePath.get()));
}
const gchar* webkit_web_context_get_favicon_database_directory(WebKitWebContext *context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
WebKitWebContextPrivate* priv = context->priv;
if (priv->faviconDatabaseDirectory.isNull())
return 0;
return priv->faviconDatabaseDirectory.data();
}
WebKitFaviconDatabase* webkit_web_context_get_favicon_database(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
ensureFaviconDatabase(context);
return context->priv->faviconDatabase.get();
}
WebKitSecurityManager* webkit_web_context_get_security_manager(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
WebKitWebContextPrivate* priv = context->priv;
if (!priv->securityManager)
priv->securityManager = adoptGRef(webkitSecurityManagerCreate(context));
return priv->securityManager.get();
}
void webkit_web_context_set_additional_plugins_directory(WebKitWebContext* context, const char* directory)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(directory);
context->priv->context->setAdditionalPluginsDirectory(WebCore::filenameToString(directory));
}
struct GetPluginsAsyncData {
Vector<PluginModuleInfo> plugins;
};
WEBKIT_DEFINE_ASYNC_DATA_STRUCT(GetPluginsAsyncData)
static void webkitWebContextGetPluginThread(GSimpleAsyncResult* result, GObject* object, GCancellable*)
{
GetPluginsAsyncData* data = static_cast<GetPluginsAsyncData*>(g_simple_async_result_get_op_res_gpointer(result));
data->plugins = WEBKIT_WEB_CONTEXT(object)->priv->context->pluginInfoStore().plugins();
}
void webkit_web_context_get_plugins(WebKitWebContext* context, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
GRefPtr<GSimpleAsyncResult> result = adoptGRef(g_simple_async_result_new(G_OBJECT(context), callback, userData,
reinterpret_cast<gpointer>(webkit_web_context_get_plugins)));
g_simple_async_result_set_op_res_gpointer(result.get(), createGetPluginsAsyncData(),
reinterpret_cast<GDestroyNotify>(destroyGetPluginsAsyncData));
g_simple_async_result_run_in_thread(result.get(), webkitWebContextGetPluginThread, G_PRIORITY_DEFAULT, cancellable);
}
GList* webkit_web_context_get_plugins_finish(WebKitWebContext* context, GAsyncResult* result, GError** error)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
g_return_val_if_fail(G_IS_ASYNC_RESULT(result), 0);
GSimpleAsyncResult* simpleResult = G_SIMPLE_ASYNC_RESULT(result);
g_warn_if_fail(g_simple_async_result_get_source_tag(simpleResult) == webkit_web_context_get_plugins);
if (g_simple_async_result_propagate_error(simpleResult, error))
return 0;
GetPluginsAsyncData* data = static_cast<GetPluginsAsyncData*>(g_simple_async_result_get_op_res_gpointer(simpleResult));
GList* plugins = 0;
for (size_t i = 0; i < data->plugins.size(); ++i)
plugins = g_list_prepend(plugins, webkitPluginCreate(data->plugins[i]));
return plugins;
}
void webkit_web_context_register_uri_scheme(WebKitWebContext* context, const char* scheme, WebKitURISchemeRequestCallback callback, gpointer userData, GDestroyNotify destroyNotify)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(scheme);
g_return_if_fail(callback);
RefPtr<WebKitURISchemeHandler> handler = adoptRef(new WebKitURISchemeHandler(callback, userData, destroyNotify));
context->priv->uriSchemeHandlers.set(String::fromUTF8(scheme), handler.get());
context->priv->requestManager->registerURIScheme(String::fromUTF8(scheme));
}
gboolean webkit_web_context_get_spell_checking_enabled(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
#if ENABLE(SPELLCHECK)
return context->priv->textChecker->isSpellCheckingEnabled();
#else
return false;
#endif
}
void webkit_web_context_set_spell_checking_enabled(WebKitWebContext* context, gboolean enabled)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
#if ENABLE(SPELLCHECK)
context->priv->textChecker->setSpellCheckingEnabled(enabled);
#endif
}
const gchar* const* webkit_web_context_get_spell_checking_languages(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
#if ENABLE(SPELLCHECK)
return context->priv->textChecker->getSpellCheckingLanguages();
#else
return 0;
#endif
}
void webkit_web_context_set_spell_checking_languages(WebKitWebContext* context, const gchar* const* languages)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(languages);
#if ENABLE(SPELLCHECK)
context->priv->textChecker->setSpellCheckingLanguages(languages);
#endif
}
void webkit_web_context_set_preferred_languages(WebKitWebContext* context, const gchar* const* languageList)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
if (!languageList || !g_strv_length(const_cast<char**>(languageList)))
return;
Vector<String> languages;
for (size_t i = 0; languageList[i]; ++i)
languages.append(String::fromUTF8(languageList[i]).lower().replace("_", "-"));
WebCore::overrideUserPreferredLanguages(languages);
WebCore::languageDidChange();
}
void webkit_web_context_set_tls_errors_policy(WebKitWebContext* context, WebKitTLSErrorsPolicy policy)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
if (context->priv->tlsErrorsPolicy == policy)
return;
context->priv->tlsErrorsPolicy = policy;
bool ignoreTLSErrors = policy == WEBKIT_TLS_ERRORS_POLICY_IGNORE;
if (context->priv->context->ignoreTLSErrors() != ignoreTLSErrors)
context->priv->context->setIgnoreTLSErrors(ignoreTLSErrors);
}
WebKitTLSErrorsPolicy webkit_web_context_get_tls_errors_policy(WebKitWebContext* context)
{
g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), WEBKIT_TLS_ERRORS_POLICY_IGNORE);
return context->priv->tlsErrorsPolicy;
}
void webkit_web_context_set_web_extensions_directory(WebKitWebContext* context, const char* directory)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(directory);
context->priv->context->setInjectedBundleInitializationUserData(WebString::create(WebCore::filenameToString(directory)));
}
void webkit_web_context_set_disk_cache_directory(WebKitWebContext* context, const char* directory)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(directory);
context->priv->context->setDiskCacheDirectory(WebCore::filenameToString(directory));
}
void webkit_web_context_prefetch_dns(WebKitWebContext* context, const char* hostname)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(hostname);
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Hostname"), WebString::create(String::fromUTF8(hostname)));
context->priv->context->postMessageToInjectedBundle(String::fromUTF8("PrefetchDNS"), ImmutableDictionary::adopt(message).get());
}
WebKitDownload* webkitWebContextGetOrCreateDownload(DownloadProxy* downloadProxy)
{
GRefPtr<WebKitDownload> download = downloadsMap().get(downloadProxy);
if (download)
return download.get();
download = adoptGRef(webkitDownloadCreate(downloadProxy));
downloadsMap().set(downloadProxy, download.get());
return download.get();
}
WebKitDownload* webkitWebContextStartDownload(WebKitWebContext* context, const char* uri, WebPageProxy* initiatingPage)
{
WebCore::ResourceRequest request(String::fromUTF8(uri));
DownloadProxy* downloadProxy = context->priv->context->download(initiatingPage, request);
WebKitDownload* download = webkitDownloadCreateForRequest(downloadProxy, request);
downloadsMap().set(downloadProxy, download);
return download;
}
void webkitWebContextRemoveDownload(DownloadProxy* downloadProxy)
{
downloadsMap().remove(downloadProxy);
}
void webkitWebContextDownloadStarted(WebKitWebContext* context, WebKitDownload* download)
{
g_signal_emit(context, signals[DOWNLOAD_STARTED], 0, download);
}
WebContext* webkitWebContextGetContext(WebKitWebContext* context)
{
g_assert(WEBKIT_IS_WEB_CONTEXT(context));
return context->priv->context.get();
}
WebSoupRequestManagerProxy* webkitWebContextGetRequestManager(WebKitWebContext* context)
{
return context->priv->requestManager.get();
}
void webkitWebContextReceivedURIRequest(WebKitWebContext* context, WebKitURISchemeRequest* request)
{
String scheme(String::fromUTF8(webkit_uri_scheme_request_get_scheme(request)));
RefPtr<WebKitURISchemeHandler> handler = context->priv->uriSchemeHandlers.get(scheme);
ASSERT(handler.get());
if (!handler->hasCallback())
return;
context->priv->uriSchemeRequests.set(webkitURISchemeRequestGetID(request), request);
handler->performCallback(request);
}
void webkitWebContextDidFailToLoadURIRequest(WebKitWebContext* context, uint64_t requestID)
{
GRefPtr<WebKitURISchemeRequest> request = context->priv->uriSchemeRequests.get(requestID);
if (!request.get())
return;
webkitURISchemeRequestCancel(request.get());
}
void webkitWebContextDidFinishURIRequest(WebKitWebContext* context, uint64_t requestID)
{
context->priv->uriSchemeRequests.remove(requestID);
}
void webkitWebContextCreatePageForWebView(WebKitWebContext* context, WebKitWebView* webView, WebKitWebViewGroup* webViewGroup)
{
WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
WebPageGroup* pageGroup = webViewGroup ? webkitWebViewGroupGetPageGroup(webViewGroup) : 0;
webkitWebViewBaseCreateWebPage(webViewBase, context->priv->context.get(), pageGroup);
WebPageProxy* page = webkitWebViewBaseGetPage(webViewBase);
context->priv->webViews.set(page->pageID(), webView);
if (!pageGroup && !context->priv->defaultWebViewGroup)
context->priv->defaultWebViewGroup = adoptGRef(webkitWebViewGroupCreate(page->pageGroup()));
}
void webkitWebContextWebViewDestroyed(WebKitWebContext* context, WebKitWebView* webView)
{
WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
context->priv->webViews.remove(page->pageID());
}
WebKitWebView* webkitWebContextGetWebViewForPage(WebKitWebContext* context, WebPageProxy* page)
{
return page ? context->priv->webViews.get(page->pageID()) : 0;
}
WebKitWebViewGroup* webkitWebContextGetDefaultWebViewGroup(WebKitWebContext* context)
{
return context->priv->defaultWebViewGroup.get();
}