[epiphany/pgriffis/web-extension-gtask] WebExtensions: Add error reporting and ability to define async handlers



commit 375e44a2f34bf9911f1c57dc5bb1837190a5369d
Author: Patrick Griffis <pgriffis igalia com>
Date:   Thu May 26 13:08:53 2022 -0500

    WebExtensions: Add error reporting and ability to define async handlers
    
    Now each API handler is backed by a GTask that can get errors.
    
    For now we don't use the async ability but now its possible.

 src/webextension/api/notifications.c          |  39 +++++---
 src/webextension/api/notifications.h          |   7 +-
 src/webextension/api/pageaction.c             |  83 +++++++++++------
 src/webextension/api/pageaction.h             |   7 +-
 src/webextension/api/runtime.c                |  58 ++++++------
 src/webextension/api/runtime.h                |   7 +-
 src/webextension/api/storage.c                |  63 ++++++++-----
 src/webextension/api/storage.h                |   7 +-
 src/webextension/api/tabs.c                   | 124 +++++++++++++++++---------
 src/webextension/api/tabs.h                   |   7 +-
 src/webextension/ephy-web-extension-manager.c |  65 ++++++++++----
 src/webextension/ephy-web-extension.h         |  19 +++-
 12 files changed, 320 insertions(+), 166 deletions(-)
---
diff --git a/src/webextension/api/notifications.c b/src/webextension/api/notifications.c
index 8e33bd783..5a367c174 100644
--- a/src/webextension/api/notifications.c
+++ b/src/webextension/api/notifications.c
@@ -26,9 +26,10 @@
 #include "notifications.h"
 
 static char *
-notifications_handler_create (EphyWebExtension *self,
-                              char             *name,
-                              JSCValue         *args)
+notifications_handler_create (EphyWebExtension  *self,
+                              char              *name,
+                              JSCValue          *args,
+                              GError           **error)
 {
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
   g_autofree char *title_str = NULL;
@@ -37,8 +38,10 @@ notifications_handler_create (EphyWebExtension *self,
   g_autoptr (JSCValue) message = NULL;
   EphyNotification *notify;
 
-  if (!jsc_value_is_object (value))
+  if (!jsc_value_is_object (value)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   title = jsc_value_object_get_property (value, "title");
   title_str = jsc_value_to_string (title);
@@ -52,26 +55,36 @@ notifications_handler_create (EphyWebExtension *self,
   return NULL;
 }
 
-static EphyWebExtensionApiHandler notifications_handlers[] = {
+static EphyWebExtensionSyncApiHandler notifications_handlers[] = {
   {"create", notifications_handler_create},
-  {NULL, NULL},
 };
 
-char *
+void
 ephy_web_extension_api_notifications_handler (EphyWebExtension *self,
                                               char             *name,
-                                              JSCValue         *args)
+                                              JSCValue         *args,
+                                              GTask            *task)
 {
+  g_autoptr (GError) error = NULL;
   guint idx;
 
   for (idx = 0; idx < G_N_ELEMENTS (notifications_handlers); idx++) {
-    EphyWebExtensionApiHandler handler = notifications_handlers[idx];
+    EphyWebExtensionSyncApiHandler handler = notifications_handlers[idx];
+    char *ret;
+
+    if (g_strcmp0 (handler.name, name) == 0) {
+      ret = handler.execute (self, name, args, &error);
+
+      if (error)
+        g_task_return_error (task, g_steal_pointer (&error));
+      else
+        g_task_return_pointer (task, ret, g_free);
 
-    if (g_strcmp0 (handler.name, name) == 0)
-      return handler.execute (self, name, args);
+      return;
+    }
   }
 
   g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name);
-
-  return NULL;
+  error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not Implemented");
+  g_task_return_error (task, g_steal_pointer (&error));
 }
diff --git a/src/webextension/api/notifications.h b/src/webextension/api/notifications.h
index f0f5434a7..eb3a455a6 100644
--- a/src/webextension/api/notifications.h
+++ b/src/webextension/api/notifications.h
@@ -25,8 +25,9 @@
 
 G_BEGIN_DECLS
 
-char *ephy_web_extension_api_notifications_handler (EphyWebExtension *self,
-                                                    char             *name,
-                                                    JSCValue         *args);
+void ephy_web_extension_api_notifications_handler (EphyWebExtension *self,
+                                                    char            *name,
+                                                    JSCValue        *args,
+                                                    GTask           *task);
 
 G_END_DECLS
diff --git a/src/webextension/api/pageaction.c b/src/webextension/api/pageaction.c
index 70b6df697..aa52a0c56 100644
--- a/src/webextension/api/pageaction.c
+++ b/src/webextension/api/pageaction.c
@@ -54,9 +54,10 @@ pageaction_get_action (EphyWebExtension *self,
 }
 
 static char *
-pageaction_handler_seticon (EphyWebExtension *self,
-                            char             *name,
-                            JSCValue         *args)
+pageaction_handler_seticon (EphyWebExtension  *self,
+                            char              *name,
+                            JSCValue          *args,
+                            GError           **error)
 {
   GtkWidget *action;
   g_autoptr (JSCValue) path = NULL;
@@ -64,8 +65,10 @@ pageaction_handler_seticon (EphyWebExtension *self,
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
 
   action = pageaction_get_action (self, value);
-  if (!action)
+  if (!action) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   path = jsc_value_object_get_property (value, "path");
   pixbuf = ephy_web_extension_load_pixbuf (self, jsc_value_to_string (path));
@@ -76,17 +79,20 @@ pageaction_handler_seticon (EphyWebExtension *self,
 }
 
 static char *
-pageaction_handler_settitle (EphyWebExtension *self,
-                             char             *name,
-                             JSCValue         *args)
+pageaction_handler_settitle (EphyWebExtension  *self,
+                             char              *name,
+                             JSCValue          *args,
+                             GError           **error)
 {
   GtkWidget *action;
   g_autoptr (JSCValue) title = NULL;
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
 
   action = pageaction_get_action (self, value);
-  if (!action)
+  if (!action) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   title = jsc_value_object_get_property (value, "title");
   gtk_widget_set_tooltip_text (action, jsc_value_to_string (title));
@@ -95,17 +101,20 @@ pageaction_handler_settitle (EphyWebExtension *self,
 }
 
 static char *
-pageaction_handler_gettitle (EphyWebExtension *self,
-                             char             *name,
-                             JSCValue         *args)
+pageaction_handler_gettitle (EphyWebExtension  *self,
+                             char              *name,
+                             JSCValue          *args,
+                             GError           **error)
 {
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
   GtkWidget *action;
   g_autofree char *title = NULL;
 
   action = pageaction_get_action (self, value);
-  if (!action)
+  if (!action) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   title = gtk_widget_get_tooltip_text (action);
 
@@ -113,16 +122,19 @@ pageaction_handler_gettitle (EphyWebExtension *self,
 }
 
 static char *
-pageaction_handler_show (EphyWebExtension *self,
-                         char             *name,
-                         JSCValue         *args)
+pageaction_handler_show (EphyWebExtension  *self,
+                         char              *name,
+                         JSCValue          *args,
+                         GError           **error)
 {
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
   GtkWidget *action;
 
   action = pageaction_get_action (self, value);
-  if (!action)
+  if (!action) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   gtk_widget_set_visible (action, TRUE);
 
@@ -130,46 +142,59 @@ pageaction_handler_show (EphyWebExtension *self,
 }
 
 static char *
-pageaction_handler_hide (EphyWebExtension *self,
-                         char             *name,
-                         JSCValue         *args)
+pageaction_handler_hide (EphyWebExtension  *self,
+                         char              *name,
+                         JSCValue          *args,
+                         GError           **error)
 {
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
   GtkWidget *action;
 
   action = pageaction_get_action (self, value);
-  if (!action)
+  if (!action) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   gtk_widget_set_visible (action, FALSE);
 
   return NULL;
 }
 
-static EphyWebExtensionApiHandler pageaction_handlers[] = {
+static EphyWebExtensionSyncApiHandler pageaction_handlers[] = {
   {"setIcon", pageaction_handler_seticon},
   {"setTitle", pageaction_handler_settitle},
   {"getTitle", pageaction_handler_gettitle},
   {"show", pageaction_handler_show},
   {"hide", pageaction_handler_hide},
-  {NULL, NULL},
 };
 
-char *
+void
 ephy_web_extension_api_pageaction_handler (EphyWebExtension *self,
                                            char             *name,
-                                           JSCValue         *args)
+                                           JSCValue         *args,
+                                           GTask            *task)
 {
+  g_autoptr (GError) error = NULL;
   guint idx;
 
   for (idx = 0; idx < G_N_ELEMENTS (pageaction_handlers); idx++) {
-    EphyWebExtensionApiHandler handler = pageaction_handlers[idx];
+    EphyWebExtensionSyncApiHandler handler = pageaction_handlers[idx];
+    char *ret;
 
-    if (g_strcmp0 (handler.name, name) == 0)
-      return handler.execute (self, name, args);
+    if (g_strcmp0 (handler.name, name) == 0) {
+      ret = handler.execute (self, name, args, &error);
+
+      if (error)
+        g_task_return_error (task, g_steal_pointer (&error));
+      else
+        g_task_return_pointer (task, ret, g_free);
+
+      return;
+    }
   }
 
   g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name);
-
-  return NULL;
+  error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not Implemented");
+  g_task_return_error (task, g_steal_pointer (&error));
 }
diff --git a/src/webextension/api/pageaction.h b/src/webextension/api/pageaction.h
index af3ce840b..293bf7825 100644
--- a/src/webextension/api/pageaction.h
+++ b/src/webextension/api/pageaction.h
@@ -25,8 +25,9 @@
 
 G_BEGIN_DECLS
 
-char *ephy_web_extension_api_pageaction_handler (EphyWebExtension *self,
-                                                 char             *name,
-                                                 JSCValue         *args);
+void ephy_web_extension_api_pageaction_handler (EphyWebExtension *self,
+                                                 char            *name,
+                                                 JSCValue        *args,
+                                                 GTask           *task);
 
 G_END_DECLS
diff --git a/src/webextension/api/runtime.c b/src/webextension/api/runtime.c
index 4f9b1be1e..988cc8799 100644
--- a/src/webextension/api/runtime.c
+++ b/src/webextension/api/runtime.c
@@ -28,9 +28,10 @@
 #include "ephy-shell.h"
 
 static char *
-runtime_handler_get_browser_info (EphyWebExtension *self,
-                                  char             *name,
-                                  JSCValue         *args)
+runtime_handler_get_browser_info (EphyWebExtension  *self,
+                                  char              *name,
+                                  JSCValue          *args,
+                                  GError           **error)
 {
   g_autoptr (JsonBuilder) builder = json_builder_new ();
   g_autoptr (JsonNode) root = NULL;
@@ -46,9 +47,10 @@ runtime_handler_get_browser_info (EphyWebExtension *self,
 }
 
 static char *
-runtime_handler_send_message (EphyWebExtension *self,
-                              char             *name,
-                              JSCValue         *args)
+runtime_handler_send_message (EphyWebExtension  *self,
+                              char              *name,
+                              JSCValue          *args,
+                              GError           **error)
 {
   EphyShell *shell = ephy_shell_get_default ();
   EphyWebExtensionManager *manager = ephy_shell_get_web_extension_manager (shell);
@@ -63,9 +65,10 @@ runtime_handler_send_message (EphyWebExtension *self,
 }
 
 static char *
-runtime_handler_open_options_page (EphyWebExtension *self,
-                                   char             *name,
-                                   JSCValue         *args)
+runtime_handler_open_options_page (EphyWebExtension  *self,
+                                   char              *name,
+                                   JSCValue          *args,
+                                   GError           **error)
 {
   const char *data = ephy_web_extension_get_option_ui_page (self);
 
@@ -87,37 +90,38 @@ runtime_handler_open_options_page (EphyWebExtension *self,
   return NULL;
 }
 
-static char *
-runtime_handler_set_uninstall_url (EphyWebExtension *self,
-                                   char             *name,
-                                   JSCValue         *args)
-{
-  return NULL;
-}
-
-static EphyWebExtensionApiHandler runtime_handlers[] = {
+static EphyWebExtensionSyncApiHandler runtime_handlers[] = {
   {"getBrowserInfo", runtime_handler_get_browser_info},
   {"sendMessage", runtime_handler_send_message},
   {"openOptionsPage", runtime_handler_open_options_page},
-  {"setUninstallURL", runtime_handler_set_uninstall_url},
-  {NULL, NULL},
 };
 
-char *
+void
 ephy_web_extension_api_runtime_handler (EphyWebExtension *self,
                                         char             *name,
-                                        JSCValue         *args)
+                                        JSCValue         *args,
+                                        GTask            *task)
 {
+  g_autoptr (GError) error = NULL;
   guint idx;
 
   for (idx = 0; idx < G_N_ELEMENTS (runtime_handlers); idx++) {
-    EphyWebExtensionApiHandler handler = runtime_handlers[idx];
+    EphyWebExtensionSyncApiHandler handler = runtime_handlers[idx];
+    char *ret;
 
-    if (g_strcmp0 (handler.name, name) == 0)
-      return handler.execute (self, name, args);
+    if (g_strcmp0 (handler.name, name) == 0) {
+      ret = handler.execute (self, name, args, &error);
+
+      if (error)
+        g_task_return_error (task, g_steal_pointer (&error));
+      else
+        g_task_return_pointer (task, ret, g_free);
+
+      return;
+    }
   }
 
   g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name);
-
-  return NULL;
+  error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not Implemented");
+  g_task_return_error (task, g_steal_pointer (&error));
 }
diff --git a/src/webextension/api/runtime.h b/src/webextension/api/runtime.h
index 207901700..ed90dfb77 100644
--- a/src/webextension/api/runtime.h
+++ b/src/webextension/api/runtime.h
@@ -25,8 +25,9 @@
 
 G_BEGIN_DECLS
 
-char *ephy_web_extension_api_runtime_handler (EphyWebExtension *self,
-                                              char             *name,
-                                              JSCValue         *args);
+void ephy_web_extension_api_runtime_handler (EphyWebExtension *self,
+                                              char            *name,
+                                              JSCValue        *args,
+                                              GTask           *task);
 
 G_END_DECLS
diff --git a/src/webextension/api/storage.c b/src/webextension/api/storage.c
index 9f048b1df..c4da61a28 100644
--- a/src/webextension/api/storage.c
+++ b/src/webextension/api/storage.c
@@ -58,17 +58,20 @@ strv_from_value (JSCValue *array)
 }
 
 static char *
-storage_handler_local_set (EphyWebExtension *self,
-                           char             *name,
-                           JSCValue         *args)
+storage_handler_local_set (EphyWebExtension  *self,
+                           char              *name,
+                           JSCValue          *args,
+                           GError           **error)
 {
   JsonNode *local_storage = ephy_web_extension_get_local_storage (self);
   JsonObject *local_storage_obj = json_node_get_object (local_storage);
   g_auto (GStrv) keys = NULL;
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
 
-  if (!jsc_value_is_object (value))
+  if (!jsc_value_is_object (value)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   keys = jsc_value_object_enumerate_properties (value);
 
@@ -83,9 +86,10 @@ storage_handler_local_set (EphyWebExtension *self,
 }
 
 static char *
-storage_handler_local_get (EphyWebExtension *self,
-                           char             *name,
-                           JSCValue         *args)
+storage_handler_local_get (EphyWebExtension  *self,
+                           char              *name,
+                           JSCValue          *args,
+                           GError           **error)
 {
   JsonNode *local_storage = ephy_web_extension_get_local_storage (self);
   JsonObject *local_storage_obj = json_node_get_object (local_storage);
@@ -143,9 +147,10 @@ end_get:
 }
 
 static char *
-storage_handler_local_remove (EphyWebExtension *self,
-                              char             *name,
-                              JSCValue         *args)
+storage_handler_local_remove (EphyWebExtension  *self,
+                              char              *name,
+                              JSCValue          *args,
+                              GError           **error)
 {
   JsonNode *local_storage = ephy_web_extension_get_local_storage (self);
   JsonObject *local_storage_obj = json_node_get_object (local_storage);
@@ -171,42 +176,56 @@ end_remove:
 }
 
 static char *
-storage_handler_local_clear (EphyWebExtension *self,
-                             char             *name,
-                             JSCValue         *args)
+storage_handler_local_clear (EphyWebExtension  *self,
+                             char              *name,
+                             JSCValue          *args,
+                             GError           **error)
 {
   ephy_web_extension_clear_local_storage (self);
   ephy_web_extension_save_local_storage (self);
   return NULL;
 }
 
-static EphyWebExtensionApiHandler storage_handlers[] = {
+static EphyWebExtensionSyncApiHandler storage_handlers[] = {
   {"local.set", storage_handler_local_set},
   {"local.get", storage_handler_local_get},
   {"local.remove", storage_handler_local_remove},
   {"local.clear", storage_handler_local_clear},
 };
 
-char *
+void
 ephy_web_extension_api_storage_handler (EphyWebExtension *self,
                                         char             *name,
-                                        JSCValue         *args)
+                                        JSCValue         *args,
+                                        GTask            *task)
 {
+  g_autoptr (GError) error = NULL;
   guint idx;
 
   if (!ephy_web_extension_has_permission (self, "storage")) {
     g_warning ("Extension %s tried to use storage without permission.", ephy_web_extension_get_name (self));
-    return NULL;
+    error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "Permission Denied");
+    g_task_return_error (task, g_steal_pointer (&error));
+    return;
   }
 
   for (idx = 0; idx < G_N_ELEMENTS (storage_handlers); idx++) {
-    EphyWebExtensionApiHandler handler = storage_handlers[idx];
+    EphyWebExtensionSyncApiHandler handler = storage_handlers[idx];
+    char *ret;
+
+    if (g_strcmp0 (handler.name, name) == 0) {
+      ret = handler.execute (self, name, args, &error);
+
+      if (error)
+        g_task_return_error (task, g_steal_pointer (&error));
+      else
+        g_task_return_pointer (task, ret, g_free);
 
-    if (g_strcmp0 (handler.name, name) == 0)
-      return handler.execute (self, name, args);
+      return;
+    }
   }
 
   g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name);
-
-  return NULL;
+  error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not Implemented");
+  g_task_return_error (task, g_steal_pointer (&error));
 }
diff --git a/src/webextension/api/storage.h b/src/webextension/api/storage.h
index 18ff87de9..a7bcbab0e 100644
--- a/src/webextension/api/storage.h
+++ b/src/webextension/api/storage.h
@@ -28,8 +28,9 @@
 
 G_BEGIN_DECLS
 
-char *ephy_web_extension_api_storage_handler (EphyWebExtension *self,
-                                              char             *name,
-                                              JSCValue         *value);
+void ephy_web_extension_api_storage_handler (EphyWebExtension *self,
+                                              char            *name,
+                                              JSCValue        *value,
+                                              GTask           *task);
 
 G_END_DECLS
diff --git a/src/webextension/api/tabs.c b/src/webextension/api/tabs.c
index 66d264319..053a87a8d 100644
--- a/src/webextension/api/tabs.c
+++ b/src/webextension/api/tabs.c
@@ -147,9 +147,10 @@ get_number_property (JSCValue   *args,
 }
 
 static char *
-tabs_handler_query (EphyWebExtension *self,
-                    char             *name,
-                    JSCValue         *args)
+tabs_handler_query (EphyWebExtension  *self,
+                    char              *name,
+                    JSCValue          *args,
+                    GError           **error)
 {
   g_autoptr (JsonBuilder) builder = json_builder_new ();
   g_autoptr (JsonNode) root = NULL;
@@ -223,9 +224,10 @@ tabs_handler_query (EphyWebExtension *self,
 }
 
 static char *
-tabs_handler_insert_css (EphyWebExtension *self,
-                         char             *name,
-                         JSCValue         *args)
+tabs_handler_insert_css (EphyWebExtension  *self,
+                         char              *name,
+                         JSCValue          *args,
+                         GError           **error)
 {
   EphyShell *shell = ephy_shell_get_default ();
   WebKitUserContentManager *ucm;
@@ -244,19 +246,25 @@ tabs_handler_insert_css (EphyWebExtension *self,
     obj = g_steal_pointer (&tab_id_value);
   }
 
-  if (!jsc_value_is_object (obj))
+  if (!jsc_value_is_object (obj)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   if (!tab_id_value)
     target_web_view = WEBKIT_WEB_VIEW (ephy_shell_get_active_web_view (shell));
   else
     target_web_view = get_web_view_for_tab_id (shell, jsc_value_to_int32 (tab_id_value), NULL);
 
-  if (!target_web_view)
+  if (!target_web_view) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
-  if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE))
+  if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "Permission Denied");
     return NULL;
+  }
 
   ucm = webkit_web_view_get_user_content_manager (target_web_view);
 
@@ -270,9 +278,10 @@ tabs_handler_insert_css (EphyWebExtension *self,
 }
 
 static char *
-tabs_handler_remove_css (EphyWebExtension *self,
-                         char             *name,
-                         JSCValue         *args)
+tabs_handler_remove_css (EphyWebExtension  *self,
+                         char              *name,
+                         JSCValue          *args,
+                         GError           **error)
 {
   EphyShell *shell = ephy_shell_get_default ();
   JSCValue *code;
@@ -291,19 +300,25 @@ tabs_handler_remove_css (EphyWebExtension *self,
     obj = g_steal_pointer (&tab_id_value);
   }
 
-  if (!jsc_value_is_object (obj))
+  if (!jsc_value_is_object (obj)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   if (!tab_id_value)
     target_web_view = WEBKIT_WEB_VIEW (ephy_shell_get_active_web_view (shell));
   else
     target_web_view = get_web_view_for_tab_id (shell, jsc_value_to_int32 (tab_id_value), NULL);
 
-  if (!target_web_view)
+  if (!target_web_view) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
-  if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE))
+  if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "Permission Denied");
     return NULL;
+  }
 
   ucm = webkit_web_view_get_user_content_manager (target_web_view);
 
@@ -316,9 +331,10 @@ tabs_handler_remove_css (EphyWebExtension *self,
 }
 
 static char *
-tabs_handler_get (EphyWebExtension *self,
-                  char             *name,
-                  JSCValue         *args)
+tabs_handler_get (EphyWebExtension  *self,
+                  char              *name,
+                  JSCValue          *args,
+                  GError           **error)
 {
   EphyShell *shell = ephy_shell_get_default ();
   g_autoptr (JsonBuilder) builder = json_builder_new ();
@@ -328,12 +344,16 @@ tabs_handler_get (EphyWebExtension *self,
   EphyWindow *parent_window;
 
   tab_id_value = jsc_value_object_get_property_at_index (args, 0);
-  if (!jsc_value_is_number (tab_id_value))
+  if (!jsc_value_is_number (tab_id_value)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   target_web_view = EPHY_WEB_VIEW (get_web_view_for_tab_id (shell, jsc_value_to_int32 (args), 
&parent_window));
-  if (!target_web_view)
+  if (!target_web_view) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   add_web_view_to_json (builder, parent_window, target_web_view,
                         ephy_web_extension_has_tab_or_host_permission (self, target_web_view, TRUE));
@@ -343,9 +363,10 @@ tabs_handler_get (EphyWebExtension *self,
 }
 
 static char *
-tabs_handler_execute_script (EphyWebExtension *self,
-                             char             *name,
-                             JSCValue         *args)
+tabs_handler_execute_script (EphyWebExtension  *self,
+                             char              *name,
+                             JSCValue          *args,
+                             GError           **error)
 {
   g_autoptr (JSCValue) code_value = NULL;
   g_autoptr (JSCValue) file_value = NULL;
@@ -364,8 +385,10 @@ tabs_handler_execute_script (EphyWebExtension *self,
     obj = g_steal_pointer (&tab_id_value);
   }
 
-  if (!jsc_value_is_object (obj))
+  if (!jsc_value_is_object (obj)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   file_value = jsc_value_object_get_property (obj, "file");
   code_value = jsc_value_object_get_property (obj, "code");
@@ -376,7 +399,7 @@ tabs_handler_execute_script (EphyWebExtension *self,
     g_autofree char *resource_path = jsc_value_to_string (file_value);
     code = ephy_web_extension_get_resource_as_string (self, resource_path[0] == '/' ? resource_path + 1 : 
resource_path);
   } else {
-    g_warning ("tabs.executeScript called without usable code");
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
   }
 
@@ -386,8 +409,10 @@ tabs_handler_execute_script (EphyWebExtension *self,
     target_web_view = get_web_view_for_tab_id (shell, jsc_value_to_int32 (tab_id_value), NULL);
 
   if (code && target_web_view) {
-    if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE))
+    if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE)) {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "Permission Denied");
       return NULL;
+    }
 
     webkit_web_view_run_javascript_in_world (target_web_view,
                                              code,
@@ -401,9 +426,10 @@ tabs_handler_execute_script (EphyWebExtension *self,
 }
 
 static char *
-tabs_handler_send_message (EphyWebExtension *self,
-                           char             *name,
-                           JSCValue         *args)
+tabs_handler_send_message (EphyWebExtension  *self,
+                           char              *name,
+                           JSCValue          *args,
+                           GError           **error)
 {
   g_autoptr (JSCValue) tab_id_value = NULL;
   g_autoptr (JSCValue) message_value = NULL;
@@ -413,12 +439,16 @@ tabs_handler_send_message (EphyWebExtension *self,
   WebKitWebView *target_web_view;
 
   tab_id_value = jsc_value_object_get_property_at_index (args, 0);
-  if (!jsc_value_is_number (tab_id_value))
+  if (!jsc_value_is_number (tab_id_value)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   message_value = jsc_value_object_get_property_at_index (args, 1);
-  if (jsc_value_is_undefined (message_value))
+  if (jsc_value_is_undefined (message_value)) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid Arguments");
     return NULL;
+  }
 
   serialized_message = jsc_value_to_json (message_value, 0);
   code = g_strdup_printf ("window.browser.runtime.onMessage._emit(JSON.parse('%s'));", serialized_message);
@@ -426,8 +456,10 @@ tabs_handler_send_message (EphyWebExtension *self,
   target_web_view = get_web_view_for_tab_id (shell, jsc_value_to_int32 (tab_id_value), NULL);
 
   if (target_web_view) {
-    if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE))
+    if (!ephy_web_extension_has_host_permission (self, EPHY_WEB_VIEW (target_web_view), TRUE)) {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "Permission Denied");
       return NULL;
+    }
 
     webkit_web_view_run_javascript_in_world (target_web_view,
                                              code,
@@ -441,31 +473,41 @@ tabs_handler_send_message (EphyWebExtension *self,
   return NULL;
 }
 
-static EphyWebExtensionApiHandler tabs_handlers[] = {
+static EphyWebExtensionSyncApiHandler tabs_handlers[] = {
   {"query", tabs_handler_query},
   {"insertCSS", tabs_handler_insert_css},
   {"removeCSS", tabs_handler_remove_css},
   {"get", tabs_handler_get},
   {"executeScript", tabs_handler_execute_script},
   {"sendMessage", tabs_handler_send_message},
-  {NULL, NULL},
 };
 
-char *
+void
 ephy_web_extension_api_tabs_handler (EphyWebExtension *self,
                                      char             *name,
-                                     JSCValue         *args)
+                                     JSCValue         *args,
+                                     GTask            *task)
 {
+  g_autoptr (GError) error = NULL;
   guint idx;
 
   for (idx = 0; idx < G_N_ELEMENTS (tabs_handlers); idx++) {
-    EphyWebExtensionApiHandler handler = tabs_handlers[idx];
+    EphyWebExtensionSyncApiHandler handler = tabs_handlers[idx];
+    char *ret;
+
+    if (g_strcmp0 (handler.name, name) == 0) {
+      ret = handler.execute (self, name, args, &error);
 
-    if (g_strcmp0 (handler.name, name) == 0)
-      return handler.execute (self, name, args);
+      if (error)
+        g_task_return_error (task, g_steal_pointer (&error));
+      else
+        g_task_return_pointer (task, ret, g_free);
+
+      return;
+    }
   }
 
   g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name);
-
-  return NULL;
+  error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not Implemented");
+  g_task_return_error (task, g_steal_pointer (&error));
 }
diff --git a/src/webextension/api/tabs.h b/src/webextension/api/tabs.h
index 92ba490cc..d9a85049f 100644
--- a/src/webextension/api/tabs.h
+++ b/src/webextension/api/tabs.h
@@ -27,8 +27,9 @@
 
 G_BEGIN_DECLS
 
-char *ephy_web_extension_api_tabs_handler (EphyWebExtension *self,
-                                           char             *name,
-                                           JSCValue         *value);
+void ephy_web_extension_api_tabs_handler (EphyWebExtension *self,
+                                           char            *name,
+                                           JSCValue        *value,
+                                           GTask           *task);
 
 G_END_DECLS
diff --git a/src/webextension/ephy-web-extension-manager.c b/src/webextension/ephy-web-extension-manager.c
index 9b647d5be..16926c04e 100644
--- a/src/webextension/ephy-web-extension-manager.c
+++ b/src/webextension/ephy-web-extension-manager.c
@@ -55,7 +55,7 @@ struct _EphyWebExtensionManager {
 
 G_DEFINE_TYPE (EphyWebExtensionManager, ephy_web_extension_manager, G_TYPE_OBJECT)
 
-EphyWebExtensionApiHandler api_handlers[] = {
+EphyWebExtensionAsyncApiHandler api_handlers[] = {
   {"notifications", ephy_web_extension_api_notifications_handler},
   {"pageAction", ephy_web_extension_api_pageaction_handler},
   {"runtime", ephy_web_extension_api_runtime_handler},
@@ -446,6 +446,50 @@ respond_with_error (WebKitUserMessage *message,
   webkit_user_message_send_reply (message, reply);
 }
 
+typedef struct {
+  WebKitUserMessage *message;
+  JSCValue *args;
+} ApiHandlerData;
+
+static void
+api_handler_data_free (ApiHandlerData *data)
+{
+  g_object_unref (data->message);
+  g_object_unref (data->args);
+  g_free (data);
+}
+
+static ApiHandlerData *
+api_handler_data_new (WebKitUserMessage *message,
+                      JSCValue          *args)
+{
+  ApiHandlerData *data = g_new (ApiHandlerData, 1);
+  data->message = g_object_ref (message);
+  data->args = g_object_ref (args);
+  return data;
+}
+
+static void
+on_web_extension_api_handler_finish (EphyWebExtension *web_extension,
+                                     GAsyncResult     *result,
+                                     gpointer          user_data)
+{
+  g_autoptr (GError) error = NULL;
+  GTask *task = G_TASK (result);
+  ApiHandlerData *data = g_task_get_task_data (task);
+  g_autofree char *json = g_task_propagate_pointer (task, &error);
+  WebKitUserMessage *reply;
+
+  if (error) {
+    respond_with_error (data->message, error->message);
+  } else {
+    reply = webkit_user_message_new ("", g_variant_new_string (json ? json : ""));
+    webkit_user_message_send_reply (data->message, reply);
+  }
+
+  g_object_unref (task);
+}
+
 static gboolean
 ephy_web_extension_handle_user_message (WebKitWebContext  *context,
                                         WebKitUserMessage *message,
@@ -457,8 +501,6 @@ ephy_web_extension_handle_user_message (WebKitWebContext  *context,
   const char *name = webkit_user_message_get_name (message);
   g_auto (GStrv) split = NULL;
 
-
-
   js_context = jsc_context_new ();
   args = jsc_value_new_from_json (js_context, g_variant_get_string (webkit_user_message_get_parameters 
(message), NULL));
 
@@ -471,21 +513,14 @@ ephy_web_extension_handle_user_message (WebKitWebContext  *context,
   }
 
   for (guint idx = 0; idx < G_N_ELEMENTS (api_handlers); idx++) {
-    EphyWebExtensionApiHandler handler = api_handlers[idx];
+    EphyWebExtensionAsyncApiHandler handler = api_handlers[idx];
 
     if (g_strcmp0 (handler.name, split[0]) == 0) {
-      g_autofree char *ret = NULL;
-      g_autofree char *script = NULL;
-      WebKitUserMessage *reply;
-
-      ret = handler.execute (web_extension, split[1], args);
-      if (ret) {
-        reply = webkit_user_message_new ("", g_variant_new_take_string (g_steal_pointer (&ret)));
-      } else {
-        reply = webkit_user_message_new ("", g_variant_new_string (""));
-      }
+      /* TODO: Cancellable */
+      GTask *task = g_task_new (web_extension, NULL, 
(GAsyncReadyCallback)on_web_extension_api_handler_finish, NULL);
+      g_task_set_task_data (task, api_handler_data_new (message, args), 
(GDestroyNotify)api_handler_data_free);
 
-      webkit_user_message_send_reply (message, reply);
+      handler.execute (web_extension, split[1], args, task);
       return TRUE;
     }
   }
diff --git a/src/webextension/ephy-web-extension.h b/src/webextension/ephy-web-extension.h
index 625488c16..9cd9e64fc 100644
--- a/src/webextension/ephy-web-extension.h
+++ b/src/webextension/ephy-web-extension.h
@@ -35,14 +35,25 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (EphyWebExtension, ephy_web_extension, EPHY, WEB_EXTENSION, GObject)
 
-typedef char *(*executeHandler)(EphyWebExtension *web_extension,
-                                char             *name,
-                                JSCValue         *args);
+typedef void (*executeTaskHandler)(EphyWebExtension *web_extension,
+                                   char             *name,
+                                   JSCValue         *args,
+                                   GTask            *task);
+
+typedef char *(*executeHandler)(EphyWebExtension  *web_extension,
+                                char              *name,
+                                JSCValue          *args,
+                                GError           **error);
+
+typedef struct {
+  char *name;
+  executeTaskHandler execute;
+} EphyWebExtensionAsyncApiHandler;
 
 typedef struct {
   char *name;
   executeHandler execute;
-} EphyWebExtensionApiHandler;
+} EphyWebExtensionSyncApiHandler;
 
 GdkPixbuf             *ephy_web_extension_get_icon                        (EphyWebExtension *self,
                                                                            gint64            size);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]