WebSetting plugin implementation
authorJakub Izydorczyk <j.izydorczyk@samsung.com>
Thu, 31 Jul 2014 11:35:08 +0000 (13:35 +0200)
committerJakub Izydorczyk <j.izydorczyk@samsung.com>
Wed, 10 Sep 2014 07:52:00 +0000 (09:52 +0200)
The Web setting extension defines APIs that manages the setting states of the Web view in Web application.
Properties of the Web view that can be managed via Web setting API:
- Delete all cookies saved for the web view in the Web application
- Set a custom user agent string of the web view in Web application

This commit includes implementation of API for Web application to set custom user agent and
remove all application cookies.

Result of running tct-tizen-websetting tests: 22/22 pass.

BUG=XWALK-1063

tizen-wrt.gyp
web_setting/web_setting.cc [new file with mode: 0644]
web_setting/web_setting.gyp [new file with mode: 0644]
web_setting/web_setting.h [new file with mode: 0644]
web_setting/web_setting_api.js [new file with mode: 0644]
web_setting/web_setting_extension.cc [new file with mode: 0644]
web_setting/web_setting_extension.h [new file with mode: 0644]
web_setting/web_setting_extension_utils.h [new file with mode: 0644]
web_setting/web_setting_instance.cc [new file with mode: 0644]
web_setting/web_setting_instance.h [new file with mode: 0644]

index 03f2ed4..87bdc1a 100644 (file)
@@ -21,6 +21,7 @@
         'time/time.gyp:*',
         'tizen/tizen.gyp:*',
         'utils/utils.gyp:*',
+        'web_setting/web_setting.gyp:*',
       ],
       'conditions': [
         [ 'tizen == 1', {
diff --git a/web_setting/web_setting.cc b/web_setting/web_setting.cc
new file mode 100644 (file)
index 0000000..41df642
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "web_setting/web_setting.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <utility>
+
+#include "web_setting/web_setting_extension_utils.h"
+
+namespace {
+
+const char kRuntimeServiceName[] =  "org.crosswalkproject.Runtime1";
+const char kRuntimeRunningManagerPath[] = "/running1";
+const char kRuntimeRunningAppInterface[] =
+    "org.crosswalkproject.Running.Application1";
+
+// The runtime process exports object for each running app on the session bus.
+GDBusProxy* CreateRunningAppProxy(const std::string& app_id) {
+  GError* error = NULL;
+  GDBusConnection* connection =
+      g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
+  if (!connection) {
+    std::cerr << "Couldn't get the session bus connection: "
+              << error->message << std::endl;
+    g_error_free(error);
+    return NULL;
+  }
+
+  std::string path =
+      std::string(kRuntimeRunningManagerPath) + "/" + app_id;
+  // Every application id contains '.' character and since object path
+  // is created from application id it also contains '.' character.
+  // The d-bus proxy doesn't accept '.' character in object path
+  // And that is why the substantiation is needed here.
+  std::replace(path.begin(), path.end(), '.', '_');
+  GDBusProxy* proxy = g_dbus_proxy_new_sync(
+      connection, G_DBUS_PROXY_FLAGS_NONE, NULL, kRuntimeServiceName,
+      path.c_str(), kRuntimeRunningAppInterface, NULL, &error);
+  if (!proxy) {
+    std::cerr << "Couldn't create proxy for " << kRuntimeRunningAppInterface
+              << ": " << error->message << std::endl;
+    g_error_free(error);
+    return NULL;
+  }
+
+  return proxy;
+}
+
+}  // namespace
+
+WebSetting::WebSetting(const std::string& app_id)
+    : app_id_(app_id),
+      running_app_proxy_(NULL) {
+}
+
+WebSetting::~WebSetting() {
+  if (running_app_proxy_)
+    g_object_unref(running_app_proxy_);
+}
+
+std::unique_ptr<picojson::value> WebSetting::RemoveAllCookies() {
+  if (!running_app_proxy_) {
+    if (!(running_app_proxy_ = CreateRunningAppProxy(app_id_)))
+      return CreateResultMessage(WebApiAPIErrors::UNKNOWN_ERR);
+  }
+  GError* error = NULL;
+  GVariant* result = g_dbus_proxy_call_sync(
+      running_app_proxy_, "RemoveAllCookies", NULL,
+      G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+  if (!result) {
+    std::cerr << "Fail to call 'RemoveuserAgentAllCookies':"
+              << error->message << std::endl;
+    g_error_free(error);
+    return CreateResultMessage(WebApiAPIErrors::UNKNOWN_ERR);
+  }
+  return CreateResultMessage();
+}
+
+std::unique_ptr<picojson::value> WebSetting::SetUserAgentString(
+    const std::string& user_agent) {
+  if (!running_app_proxy_) {
+    if (!(running_app_proxy_ = CreateRunningAppProxy(app_id_)))
+      return CreateResultMessage(WebApiAPIErrors::UNKNOWN_ERR);
+  }
+  GError* error = NULL;
+  GVariant* result = g_dbus_proxy_call_sync(
+      running_app_proxy_, "SetUserAgentString",
+      g_variant_new("(s)", user_agent.c_str()),
+      G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+  if (!result) {
+    std::cerr << "Fail to call 'SetUserAgentString':"
+              << error->message << std::endl;
+    g_error_free(error);
+    return CreateResultMessage(WebApiAPIErrors::UNKNOWN_ERR);
+  }
+  return CreateResultMessage();
+}
diff --git a/web_setting/web_setting.gyp b/web_setting/web_setting.gyp
new file mode 100644 (file)
index 0000000..fe4bc14
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_websetting',
+      'type': 'loadable_module',
+      'sources': [
+        'web_setting.cc',
+        'web_setting.h',
+        'web_setting_api.js',
+        'web_setting_extension.cc',
+        'web_setting_extension.h',
+        'web_setting_extension_utils.h',
+        'web_setting_instance.cc',
+        'web_setting_instance.h',
+      ],
+      'includes': [
+        '../common/pkg-config.gypi',
+      ],
+      'variables': {
+        'packages': [
+          'glib-2.0',
+        ]
+      },
+    },
+  ],
+}
diff --git a/web_setting/web_setting.h b/web_setting/web_setting.h
new file mode 100644 (file)
index 0000000..bcaddd8
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEB_SETTING_WEB_SETTING_H_
+#define WEB_SETTING_WEB_SETTING_H_
+
+#include <gio/gio.h>
+#include <memory>
+#include <string>
+
+#include "common/picojson.h"
+
+class WebSetting {
+ public:
+  explicit WebSetting(const std::string& app_id);
+  ~WebSetting();
+
+  std::unique_ptr<picojson::value> RemoveAllCookies();
+  std::unique_ptr<picojson::value> SetUserAgentString(const std::string& user_agent);
+
+ private:
+  std::string app_id_;
+  GDBusProxy* running_app_proxy_;
+};
+
+#endif  // WEB_SETTING_WEB_SETTING_H_
diff --git a/web_setting/web_setting_api.js b/web_setting/web_setting_api.js
new file mode 100644 (file)
index 0000000..cdcba26
--- /dev/null
@@ -0,0 +1,96 @@
+var asyncCallbacks = {
+  _next_id: 0,
+  _callbacks: {},
+  key: '_callback',
+
+  // Return a callback ID number which will be contained by the native message.
+  setup: function(callback) {
+    var id = ++this._next_id;
+    this._callbacks[id] = callback;
+    return id;
+  },
+
+  dispatch: function(m) {
+    var id = m[this.key];
+    var callback = this._callbacks[id];
+    callback.call(null, m);
+    delete this._callbacks[id];
+  }
+};
+
+extension.setMessageListener(function(msg) {
+  var m = JSON.parse(msg);
+  if (typeof m[asyncCallbacks.key] === 'number') {
+    asyncCallbacks.dispatch(m);
+  } else {
+    if (m[asyncCallbacks.key] === appInfoEventCallbacks.key)
+      appInfoEventCallbacks.dispatch(m);
+    else
+      console.error('unexpected message received' + msg);
+  }
+});
+
+// Post async message to extension with callbackId saved. The extension will return
+// a message with the same callbackId to the callback set in setMessageListener.
+function postMessage(msg, callbackId) {
+  msg[asyncCallbacks.key] = callbackId;
+  extension.postMessage(JSON.stringify(msg));
+}
+
+function defineReadOnlyProperty(object, key, value) {
+  Object.defineProperty(object, key, {
+    enumerable: true,
+    writable: false,
+    value: value
+  });
+}
+
+exports.setUserAgentString = function(userAgent,
+                                      successCallback, errorCallback) {
+  if (arguments.length > 0 && typeof userAgent !== 'string' ||
+      arguments.length > 1 && (successCallback !== null &&
+      typeof successCallback !== 'function') || arguments.length > 2 &&
+      (errorCallback !== null && typeof errorCallback !== 'function')) {
+    throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+  }
+
+  var callbackId = asyncCallbacks.setup(function(result) {
+    if (result.error !== null) {
+      if (!errorCallback) {
+        return;
+      }
+      return errorCallback(new tizen.WebAPIError(result.error));
+    }
+    if (successCallback !== null) {
+      return successCallback(result.data);
+    }
+    return;
+  });
+
+  var msg = { cmd: 'SetUserAgentString', userAgentStr: userAgent };
+  postMessage(msg, callbackId);
+};
+
+exports.removeAllCookies = function(successCallback, errorCallback) {
+  if (arguments.length > 0 && (successCallback !== null &&
+      typeof successCallback !== 'function') || arguments.length > 1 &&
+      (errorCallback !== null && typeof errorCallback !== 'function')) {
+    throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+  }
+
+  var callbackId = asyncCallbacks.setup(function(result) {
+    if (result.error !== null) {
+      if (!errorCallback) {
+        return;
+      }
+      return errorCallback(new tizen.WebAPIError(result.error));
+    }
+    if (successCallback !== null) {
+      return successCallback(result.data);
+    }
+    return;
+  });
+
+  var msg = { cmd: 'RemoveAllCookies' };
+  postMessage(msg, callbackId);
+};
diff --git a/web_setting/web_setting_extension.cc b/web_setting/web_setting_extension.cc
new file mode 100644 (file)
index 0000000..108c769
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "web_setting/web_setting_extension.h"
+
+#include <string>
+
+#include "web_setting/web_setting.h"
+#include "web_setting/web_setting_instance.h"
+
+extern const char kSource_web_setting_api[];
+
+common::Extension* CreateExtension() {
+  std::string env_app_id = common::Extension::GetRuntimeVariable("app_id", 64);
+  std::string app_id = env_app_id.substr(1, env_app_id.rfind('"') - 1);
+  if (app_id.empty()) {
+    std::cerr << "Got invalid application ID." << std::endl;
+    return nullptr;
+  }
+  return new WebSettingExtension(app_id);
+}
+
+WebSettingExtension::WebSettingExtension(const std::string& app_id) {
+  current_app_.reset(new WebSetting(app_id));
+  SetExtensionName("tizen.websetting");
+  SetJavaScriptAPI(kSource_web_setting_api);
+}
+
+WebSettingExtension::~WebSettingExtension() {}
+
+common::Instance* WebSettingExtension::CreateInstance() {
+  return new WebSettingInstance(this);
+}
diff --git a/web_setting/web_setting_extension.h b/web_setting/web_setting_extension.h
new file mode 100644 (file)
index 0000000..f7e3aaf
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEB_SETTING_WEB_SETTING_EXTENSION_H_
+#define WEB_SETTING_WEB_SETTING_EXTENSION_H_
+
+#include <memory>
+#include <string>
+#include "common/extension.h"
+#include "web_setting/web_setting.h"
+
+class WebSettingExtension : public common::Extension {
+ public:
+  explicit WebSettingExtension(const std::string& app_id);
+  virtual ~WebSettingExtension();
+
+  WebSetting* current_app() { return current_app_.get(); }
+ private:
+  virtual common::Instance* CreateInstance();
+
+  std::unique_ptr<WebSetting> current_app_;
+};
+
+#endif  // WEB_SETTING_WEB_SETTING_EXTENSION_H_
diff --git a/web_setting/web_setting_extension_utils.h b/web_setting/web_setting_extension_utils.h
new file mode 100644 (file)
index 0000000..03a92a0
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEB_SETTING_WEB_SETTING_EXTENSION_UTILS_H_
+#define WEB_SETTING_WEB_SETTING_EXTENSION_UTILS_H_
+
+#include <memory>
+
+#include "common/picojson.h"
+#include "tizen/tizen.h"
+
+std::unique_ptr<picojson::value> CreateResultMessage() {
+  picojson::object obj;
+  obj["error"] = picojson::value();
+  return std::unique_ptr<picojson::value>(new picojson::value(obj));
+}
+
+std::unique_ptr<picojson::value> CreateResultMessage(
+    WebApiAPIErrors error) {
+  picojson::object obj;
+  obj["error"] = picojson::value(static_cast<double>(error));
+  return std::unique_ptr<picojson::value>(new picojson::value(obj));
+}
+
+std::unique_ptr<picojson::value> CreateResultMessage(
+    const picojson::object& data) {
+  picojson::object obj;
+  obj["data"] = picojson::value(data);
+  return std::unique_ptr<picojson::value>(new picojson::value(obj));
+}
+
+std::unique_ptr<picojson::value> CreateResultMessage(
+    const picojson::array& data) {
+  picojson::object obj;
+  obj["data"] = picojson::value(data);
+  return std::unique_ptr<picojson::value>(new picojson::value(obj));
+}
+
+std::unique_ptr<picojson::value> CreateResultMessage(
+    const picojson::value& data) {
+  picojson::object obj;
+  obj["data"] = data;
+  return std::unique_ptr<picojson::value>(new picojson::value(obj));
+}
+
+#endif  // WEB_SETTING_WEB_SETTING_EXTENSION_UTILS_H_
diff --git a/web_setting/web_setting_instance.cc b/web_setting/web_setting_instance.cc
new file mode 100644 (file)
index 0000000..08f3070
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "web_setting/web_setting_instance.h"
+
+#include <string>
+#include <memory>
+#include "common/picojson.h"
+
+namespace {
+
+const char kJSCallbackKey[] = "_callback";
+
+double GetJSCallbackId(const picojson::value& msg) {
+  assert(msg.contains(kJSCallbackKey));
+  const picojson::value& id_value = msg.get(kJSCallbackKey);
+  return id_value.get<double>();
+}
+
+void SetJSCallbackId(picojson::value& msg, double id) {
+  assert(msg.is<picojson::object>());
+  msg.get<picojson::object>()[kJSCallbackKey] = picojson::value(id);
+}
+
+}  // namespace
+
+WebSettingInstance::WebSettingInstance(WebSettingExtension* extension)
+    : extension_(extension) {
+}
+
+WebSettingInstance::~WebSettingInstance() {}
+
+void WebSettingInstance::HandleMessage(const char* message) {
+  picojson::value v;
+
+  std::string err;
+  picojson::parse(v, message, message + strlen(message), &err);
+  if (!err.empty()) {
+    std::cerr << "Error during parsing message: " << err.c_str();
+    return;
+  }
+
+  std::string cmd = v.get("cmd").to_str();
+  if (cmd == "SetUserAgentString")
+    HandleSetUserAgentString(v);
+  else if (cmd == "RemoveAllCookies")
+    HandleRemoveAllCookies(v);
+  else
+    std::cerr << "ASSERT NOT REACHED. \n";
+}
+
+void WebSettingInstance::HandleSetUserAgentString(const picojson::value &msg) {
+  std::string userAgent = msg.get("userAgentStr").to_str();
+  picojson::value *result = extension_->current_app()->
+                            SetUserAgentString(userAgent).release();
+  ReturnMessageAsync(GetJSCallbackId(msg), *result);
+  delete result;
+}
+
+void WebSettingInstance::HandleRemoveAllCookies(const picojson::value& msg) {
+  picojson::value *result = extension_->current_app()->
+                            RemoveAllCookies().release();
+  ReturnMessageAsync(GetJSCallbackId(msg), *result);
+  delete result;
+}
+
+void WebSettingInstance::ReturnMessageAsync(double callback_id,
+    picojson::value& value) {
+  SetJSCallbackId(value, callback_id);
+  PostMessage(value.serialize().c_str());
+}
diff --git a/web_setting/web_setting_instance.h b/web_setting/web_setting_instance.h
new file mode 100644 (file)
index 0000000..e887541
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) 2014 Samsung Electronics Co., Ltd. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEB_SETTING_WEB_SETTING_INSTANCE_H_
+#define WEB_SETTING_WEB_SETTING_INSTANCE_H_
+
+#include "common/extension.h"
+#include "common/picojson.h"
+#include "tizen/tizen.h"
+
+#include "web_setting/web_setting_extension.h"
+
+class WebSettingInstance : public common::Instance {
+ public:
+  explicit WebSettingInstance(WebSettingExtension* extension);
+  virtual ~WebSettingInstance();
+
+ private:
+  void HandleMessage(const char* message);
+
+  void HandleSetUserAgentString(const picojson::value& msg);
+  void HandleRemoveAllCookies(const picojson::value& msg);
+
+  void ReturnMessageAsync(double callback_id, picojson::value& value);
+
+  WebSettingExtension* extension_;
+};
+
+#endif  // WEB_SETTING_WEB_SETTING_INSTANCE_H_