WebKitUserContentFilterStore.cpp [plain text]
#include "config.h"
#include "WebKitUserContentFilterStore.h"
#include "APIContentRuleList.h"
#include "APIContentRuleListStore.h"
#include "WebKitError.h"
#include "WebKitUserContent.h"
#include "WebKitUserContentPrivate.h"
#include <WebCore/ContentExtensionError.h>
#include <glib/gi18n-lib.h>
#include <wtf/CompletionHandler.h>
#include <wtf/FileSystem.h>
#include <wtf/RefPtr.h>
#include <wtf/glib/GRefPtr.h>
#include <wtf/glib/GUniquePtr.h>
#include <wtf/glib/WTFGType.h>
enum {
PROP_0,
PROP_PATH,
};
static inline GError* toGError(WebKitUserContentFilterError code, const std::error_code error)
{
ASSERT(error);
ASSERT(error.category() == WebCore::ContentExtensions::contentExtensionErrorCategory());
return g_error_new_literal(WEBKIT_USER_CONTENT_FILTER_ERROR, code, error.message().c_str());
}
struct _WebKitUserContentFilterStorePrivate {
GUniquePtr<char> storagePath;
RefPtr<API::ContentRuleListStore> store;
};
WEBKIT_DEFINE_TYPE(WebKitUserContentFilterStore, webkit_user_content_filter_store, G_TYPE_OBJECT)
static void webkitUserContentFilterStoreGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* paramSpec)
{
WebKitUserContentFilterStore* store = WEBKIT_USER_CONTENT_FILTER_STORE(object);
switch (propID) {
case PROP_PATH:
g_value_set_string(value, webkit_user_content_filter_store_get_path(store));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
}
}
static void webkitUserContentFilterStoreSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* paramSpec)
{
WebKitUserContentFilterStore* store = WEBKIT_USER_CONTENT_FILTER_STORE(object);
switch (propID) {
case PROP_PATH:
store->priv->storagePath.reset(g_value_dup_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
}
}
static void webkitUserContentFilterStoreConstructed(GObject* object)
{
G_OBJECT_CLASS(webkit_user_content_filter_store_parent_class)->constructed(object);
WebKitUserContentFilterStore* store = WEBKIT_USER_CONTENT_FILTER_STORE(object);
store->priv->store = adoptRef(new API::ContentRuleListStore(FileSystem::stringFromFileSystemRepresentation(store->priv->storagePath.get()), false));
}
static void webkit_user_content_filter_store_class_init(WebKitUserContentFilterStoreClass* storeClass)
{
GObjectClass* gObjectClass = G_OBJECT_CLASS(storeClass);
gObjectClass->get_property = webkitUserContentFilterStoreGetProperty;
gObjectClass->set_property = webkitUserContentFilterStoreSetProperty;
gObjectClass->constructed = webkitUserContentFilterStoreConstructed;
g_object_class_install_property(
gObjectClass,
PROP_PATH,
g_param_spec_string(
"path",
_("Storage directory path"),
_("The directory where user content filters are stored"),
nullptr,
static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
}
WebKitUserContentFilterStore* webkit_user_content_filter_store_new(const gchar* storagePath)
{
g_return_val_if_fail(storagePath, nullptr);
return WEBKIT_USER_CONTENT_FILTER_STORE(g_object_new(WEBKIT_TYPE_USER_CONTENT_FILTER_STORE, "path", storagePath, nullptr));
}
const char* webkit_user_content_filter_store_get_path(WebKitUserContentFilterStore* store)
{
g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store), nullptr);
return store->priv->storagePath.get();
}
static void webkitUserContentFilterStoreSaveBytes(GRefPtr<GTask>&& task, String&& identifier, GRefPtr<GBytes>&& source)
{
size_t sourceSize;
const char* sourceData = static_cast<const char*>(g_bytes_get_data(source.get(), &sourceSize));
if (!sourceSize) {
g_task_return_error(task.get(), g_error_new_literal(WEBKIT_USER_CONTENT_FILTER_ERROR, WEBKIT_USER_CONTENT_FILTER_ERROR_INVALID_SOURCE, "Source JSON rule set cannot be empty"));
return;
}
auto* store = WEBKIT_USER_CONTENT_FILTER_STORE(g_task_get_source_object(task.get()));
store->priv->store->compileContentRuleList(identifier, String::fromUTF8(sourceData, sourceSize), [task = WTFMove(task)](RefPtr<API::ContentRuleList> contentRuleList, std::error_code error) {
if (g_task_return_error_if_cancelled(task.get()))
return;
if (error)
g_task_return_error(task.get(), toGError(WEBKIT_USER_CONTENT_FILTER_ERROR_INVALID_SOURCE, error));
else
g_task_return_pointer(task.get(), webkitUserContentFilterCreate(WTFMove(contentRuleList)), reinterpret_cast<GDestroyNotify>(webkit_user_content_filter_unref));
});
}
void webkit_user_content_filter_store_save(WebKitUserContentFilterStore* store, const gchar* identifier, GBytes* source, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
{
g_return_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store));
g_return_if_fail(identifier);
g_return_if_fail(source);
g_return_if_fail(callback);
GRefPtr<GTask> task = adoptGRef(g_task_new(store, cancellable, callback, userData));
webkitUserContentFilterStoreSaveBytes(WTFMove(task), String::fromUTF8(identifier), GRefPtr<GBytes>(source));
}
WebKitUserContentFilter* webkit_user_content_filter_store_save_finish(WebKitUserContentFilterStore* store, GAsyncResult* result, GError** error)
{
g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store), nullptr);
g_return_val_if_fail(result, nullptr);
return static_cast<WebKitUserContentFilter*>(g_task_propagate_pointer(G_TASK(result), error));
}
struct SaveTaskData {
String identifier;
};
WEBKIT_DEFINE_ASYNC_DATA_STRUCT(SaveTaskData)
void webkit_user_content_filter_store_save_from_file(WebKitUserContentFilterStore* store, const gchar* identifier, GFile* file, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
{
g_return_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store));
g_return_if_fail(identifier);
g_return_if_fail(G_IS_FILE(file));
g_return_if_fail(callback);
GRefPtr<GTask> task = adoptGRef(g_task_new(store, cancellable, callback, userData));
if (g_file_is_native(file)) {
GUniquePtr<char> filePath(g_file_get_path(file));
GRefPtr<GMappedFile> mappedFile = adoptGRef(g_mapped_file_new(filePath.get(), FALSE, nullptr));
if (mappedFile) {
GRefPtr<GBytes> source = adoptGRef(g_mapped_file_get_bytes(mappedFile.get()));
webkitUserContentFilterStoreSaveBytes(WTFMove(task), String::fromUTF8(identifier), WTFMove(source));
return;
}
}
SaveTaskData* data = createSaveTaskData();
data->identifier = String::fromUTF8(identifier);
g_task_set_task_data(task.get(), data, reinterpret_cast<GDestroyNotify>(destroySaveTaskData));
g_file_load_contents_async(file, cancellable, [](GObject* sourceObject, GAsyncResult* result, void* userData) {
GRefPtr<GTask> task = adoptGRef(G_TASK(userData));
if (g_task_return_error_if_cancelled(task.get()))
return;
char* sourceData;
size_t sourceSize;
GUniqueOutPtr<GError> error;
if (g_file_load_contents_finish(G_FILE(sourceObject), result, &sourceData, &sourceSize, nullptr, &error.outPtr())) {
SaveTaskData* data = static_cast<SaveTaskData*>(g_task_get_task_data(task.get()));
webkitUserContentFilterStoreSaveBytes(WTFMove(task), WTFMove(data->identifier), GRefPtr<GBytes>(g_bytes_new_take(sourceData, sourceSize)));
} else
g_task_return_error(task.get(), error.release());
}, task.leakRef());
}
WebKitUserContentFilter* webkit_user_content_filter_store_save_from_file_finish(WebKitUserContentFilterStore* store, GAsyncResult* result, GError** error)
{
g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store), nullptr);
g_return_val_if_fail(result, nullptr);
return static_cast<WebKitUserContentFilter*>(g_task_propagate_pointer(G_TASK(result), error));
}
void webkit_user_content_filter_store_remove(WebKitUserContentFilterStore* store, const gchar* identifier, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
{
g_return_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store));
g_return_if_fail(identifier);
g_return_if_fail(callback);
GRefPtr<GTask> task = adoptGRef(g_task_new(store, cancellable, callback, userData));
store->priv->store->removeContentRuleList(String::fromUTF8(identifier), [task = WTFMove(task)](std::error_code error) {
if (g_task_return_error_if_cancelled(task.get()))
return;
if (error) {
ASSERT(static_cast<API::ContentRuleListStore::Error>(error.value()) == API::ContentRuleListStore::Error::RemoveFailed);
g_task_return_error(task.get(), toGError(WEBKIT_USER_CONTENT_FILTER_ERROR_NOT_FOUND, error));
} else
g_task_return_boolean(task.get(), TRUE);
});
}
gboolean webkit_user_content_filter_store_remove_finish(WebKitUserContentFilterStore* store, GAsyncResult* result, GError** error)
{
g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store), FALSE);
g_return_val_if_fail(result, FALSE);
return g_task_propagate_boolean(G_TASK(result), error);
}
void webkit_user_content_filter_store_load(WebKitUserContentFilterStore* store, const gchar* identifier, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
{
g_return_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store));
g_return_if_fail(identifier);
g_return_if_fail(callback);
GRefPtr<GTask> task = adoptGRef(g_task_new(store, cancellable, callback, userData));
store->priv->store->lookupContentRuleList(String::fromUTF8(identifier), [task = WTFMove(task)](RefPtr<API::ContentRuleList> contentRuleList, std::error_code error) {
if (g_task_return_error_if_cancelled(task.get()))
return;
if (error) {
ASSERT(static_cast<API::ContentRuleListStore::Error>(error.value()) == API::ContentRuleListStore::Error::LookupFailed
|| static_cast<API::ContentRuleListStore::Error>(error.value()) == API::ContentRuleListStore::Error::VersionMismatch);
g_task_return_error(task.get(), toGError(WEBKIT_USER_CONTENT_FILTER_ERROR_NOT_FOUND, error));
} else
g_task_return_pointer(task.get(), webkitUserContentFilterCreate(WTFMove(contentRuleList)), reinterpret_cast<GDestroyNotify>(webkit_user_content_filter_unref));
});
}
WebKitUserContentFilter* webkit_user_content_filter_store_load_finish(WebKitUserContentFilterStore* store, GAsyncResult* result, GError** error)
{
g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store), nullptr);
g_return_val_if_fail(result, nullptr);
return static_cast<WebKitUserContentFilter*>(g_task_propagate_pointer(G_TASK(result), error));
}
void webkit_user_content_filter_store_fetch_identifiers(WebKitUserContentFilterStore* store, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
{
g_return_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store));
g_return_if_fail(callback);
GRefPtr<GTask> task = adoptGRef(g_task_new(store, cancellable, callback, userData));
store->priv->store->getAvailableContentRuleListIdentifiers([task = WTFMove(task)](WTF::Vector<WTF::String> identifiers) {
if (g_task_return_error_if_cancelled(task.get()))
return;
GStrv result = static_cast<GStrv>(g_new0(gchar*, identifiers.size() + 1));
for (size_t i = 0; i < identifiers.size(); ++i)
result[i] = g_strdup(identifiers[i].utf8().data());
g_task_return_pointer(task.get(), result, reinterpret_cast<GDestroyNotify>(g_strfreev));
});
}
gchar** webkit_user_content_filter_store_fetch_identifiers_finish(WebKitUserContentFilterStore* store, GAsyncResult* result)
{
g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_FILTER_STORE(store), nullptr);
g_return_val_if_fail(result, nullptr);
return static_cast<gchar**>(g_task_propagate_pointer(G_TASK(result), nullptr));
}