Enable request interceptor. 50/261750/6
authorhuayong.xu <huayong.xu@samsung.com>
Fri, 23 Jul 2021 10:21:29 +0000 (18:21 +0800)
committerhuayong.xu <huayong.xu@samsung.com>
Fri, 30 Jul 2021 07:02:23 +0000 (15:02 +0800)
Change-Id: Ibac82f53c7c847de385ed60f23c228ec06ecf981

dali-extension/web-engine-chromium/file.list
dali-extension/web-engine-chromium/tizen-web-engine-chromium.cpp
dali-extension/web-engine-chromium/tizen-web-engine-chromium.h
dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.cpp [new file with mode: 0755]
dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.h [new file with mode: 0755]
dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor.cpp
dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor.h

index c53b12f31088ff26b8ae173f575b07e55dd86b53..5ae09b25b715283c56ad1d9302eda7479ab9e76e 100755 (executable)
@@ -15,5 +15,6 @@ web_engine_chromium_plugin_src_files = \
    $(extension_src_dir)/web-engine-chromium/tizen-web-engine-load-error.cpp \
    $(extension_src_dir)/web-engine-chromium/tizen-web-engine-policy-decision.cpp \
    $(extension_src_dir)/web-engine-chromium/tizen-web-engine-request-interceptor.cpp \
+   $(extension_src_dir)/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.cpp \
    $(extension_src_dir)/web-engine-chromium/tizen-web-engine-security-origin.cpp \
    $(extension_src_dir)/web-engine-chromium/tizen-web-engine-settings.cpp
index 5cc555c5138e9b7ce3312bc6a8e796cadd930dae..942cbac2b58d09aaebb5e4a260667dc3575b0118 100755 (executable)
@@ -29,6 +29,7 @@
 #include "tizen-web-engine-http-auth-handler.h"
 #include "tizen-web-engine-load-error.h"
 #include "tizen-web-engine-policy-decision.h"
+#include "tizen-web-engine-request-interceptor.h"
 #include "tizen-web-engine-settings.h"
 
 #include <Ecore_Evas.h>
@@ -802,6 +803,19 @@ public:
     ewk_view_geolocation_permission_callback_set(mWebView, &WebViewContainerForDali::OnGeolocationPermission, &mClient);
   }
 
+  void RegisterRequestInterceptorCallback(bool isRegistered)
+  {
+    Ewk_Context* context = ewk_view_context_get(mWebView);
+    if (isRegistered)
+    {
+      ewk_context_intercept_request_callback_set(context, &WebViewContainerForDali::OnRequestIntercepted, &mClient);
+    }
+    else
+    {
+      ewk_context_intercept_request_callback_set(context, nullptr, nullptr);
+    }
+  }
+
   void UpdateDisplayArea(Dali::Rect<int32_t> displayArea)
   {
     evas_object_move(mWebView, displayArea.x, displayArea.y);
@@ -879,6 +893,13 @@ private:
     client->LoadError(std::move(loadError));
   }
 
+  static void OnRequestIntercepted(Ewk_Context*, Ewk_Intercept_Request* request, void* data)
+  {
+    auto client = static_cast<WebViewContainerClient*>(data);
+    std::unique_ptr<Dali::WebEngineRequestInterceptor> webInterceptor(new TizenWebEngineRequestInterceptor(request));
+    client->RequestIntercepted(std::move(webInterceptor));
+  }
+
   static void OnUrlChanged(void* data, Evas_Object*, void* newUrl)
   {
     auto client = static_cast<WebViewContainerClient*>(data);
@@ -1116,6 +1137,8 @@ TizenWebEngineChromium::TizenWebEngineChromium()
   : mWebViewContainer(0)
   , mJavaScriptEvaluationCount(0)
 {
+  EventThreadCallback* callback = new Dali::EventThreadCallback(Dali::MakeCallback(this, &TizenWebEngineChromium::OnRequestInterceptedEventCallback));
+  mRequestInterceptorEventTrigger = std::unique_ptr<Dali::EventThreadCallback>(callback);
 }
 
 TizenWebEngineChromium::~TizenWebEngineChromium()
@@ -1856,6 +1879,11 @@ void TizenWebEngineChromium::RegisterFormRepostDecidedCallback(WebEngineFormRepo
 void TizenWebEngineChromium::RegisterRequestInterceptorCallback(WebEngineRequestInterceptorCallback callback)
 {
   mRequestInterceptedCallback = callback;
+  if (mWebViewContainer)
+  {
+    bool isRegistered = mRequestInterceptedCallback ? true : false;
+    mWebViewContainer->RegisterRequestInterceptorCallback(isRegistered);
+  }
 }
 
 void TizenWebEngineChromium::RegisterConsoleMessageReceivedCallback(WebEngineConsoleMessageReceivedCallback callback)
@@ -1947,6 +1975,36 @@ void TizenWebEngineChromium::ScrollEdgeReached(Dali::WebEnginePlugin::ScrollEdge
   ExecuteCallback(mScrollEdgeReachedCallback, edge);
 }
 
+void TizenWebEngineChromium::RequestIntercepted(std::unique_ptr<Dali::WebEngineRequestInterceptor> interceptor)
+{
+  {
+    Mutex::ScopedLock lock(mMutex);
+    mRequestInterceptorQueue.push(std::move(interceptor));
+    // Trigger an event on main thread.
+    mRequestInterceptorEventTrigger->Trigger();
+  }
+
+  // Wait for tasks on main thread and execute tasks.
+  TizenWebEngineRequestInterceptor* requestInterceptor = static_cast<TizenWebEngineRequestInterceptor*>(interceptor.get());
+  requestInterceptor->WaitAndRunTasks();
+}
+
+void TizenWebEngineChromium::OnRequestInterceptedEventCallback()
+{
+  std::unique_ptr<Dali::WebEngineRequestInterceptor> interceptor;
+  {
+    Mutex::ScopedLock lock(mMutex);
+    interceptor = std::move(mRequestInterceptorQueue.front());
+    mRequestInterceptorQueue.pop();
+  }
+
+  ExecuteCallback(mRequestInterceptedCallback, std::move(interceptor));
+
+  // Notify ui-thread tasks ready on main thread.
+  TizenWebEngineRequestInterceptor* requestInterceptor = static_cast<TizenWebEngineRequestInterceptor*>(interceptor.get());
+  requestInterceptor->NotifyTaskReady();
+}
+
 void TizenWebEngineChromium::UrlChanged(const std::string& url)
 {
   DALI_LOG_RELEASE_INFO("#UrlChanged : %s\n", url.c_str());
index 359bf9205a92c2b36575e7a3e8fcdb0a0a4a73fd..9fbd415e789dd20ec6d6157712d2a8d73d6aa184 100755 (executable)
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
 #include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
+#include <dali/devel-api/threading/mutex.h>
 #include <dali/public-api/images/native-image-interface.h>
-#include <functional>
 
+#include <functional>
 #include <memory>
-#include <tbm_surface.h>
+#include <queue>
 #include <unordered_map>
 
+#include <tbm_surface.h>
+
 namespace Dali
 {
 class PixelData;
@@ -89,6 +93,13 @@ public:
    */
   virtual void RequestFormRepostDecided(std::unique_ptr<Dali::WebEngineFormRepostDecision> decision) = 0;
 
+  /**
+   * @brief Callback function to be called by WebViewContainer when http request
+   * need be intercepted.
+   * @param [in] request The http request interceptor.
+   */
+  virtual void RequestIntercepted(std::unique_ptr<Dali::WebEngineRequestInterceptor> interceptor) = 0;
+
   /**
    * @brief Callback function to be called by WebViewContainer when url is
    * changed.
@@ -771,6 +782,11 @@ public:
    */
   void ResponsePolicyDecided(std::unique_ptr<Dali::WebEnginePolicyDecision> policy) override;
 
+  /**
+   * @copydoc Dali::Plugin::WebViewContainerClient::RequestIntercepted()
+   */
+  void RequestIntercepted(std::unique_ptr<Dali::WebEngineRequestInterceptor> interceptor) override;
+
   /**
    * @copydoc Dali::Plugin::WebViewContainerClient::UrlChanged()
    */
@@ -858,6 +874,12 @@ public:
    */
   void PlainTextRecieved(const std::string& plainText) override;
 
+private:
+  /**
+   * @brief Event callback for request interceptor is called on main thread.
+   */
+  void OnRequestInterceptedEventCallback();
+
 private:
   WebViewContainerForDali*   mWebViewContainer;
   Dali::NativeImageSourcePtr mDaliImageSrc;
@@ -891,6 +913,10 @@ private:
 
   std::unordered_map<size_t, JavaScriptMessageHandlerCallback>      mJavaScriptEvaluationResultHandlers;
   std::unordered_map<std::string, JavaScriptMessageHandlerCallback> mJavaScriptMessageHandlers;
+
+  Dali::Mutex                                                    mMutex;
+  std::unique_ptr<Dali::EventThreadCallback>                     mRequestInterceptorEventTrigger;
+  std::queue<std::unique_ptr<Dali::WebEngineRequestInterceptor>> mRequestInterceptorQueue;
 };
 } // namespace Plugin
 } // namespace Dali
diff --git a/dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.cpp b/dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.cpp
new file mode 100755 (executable)
index 0000000..aef886e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "tizen-web-engine-request-interceptor-task-queue.h"
+
+namespace Dali
+{
+namespace Plugin
+{
+
+std::atomic<TaskQueue*> TaskQueue::mInstance { nullptr };
+std::mutex TaskQueue::mInstanceMutex;
+
+TaskQueue* TaskQueue::GetInstance()
+{
+  if(mInstance == nullptr)
+  {
+    std::lock_guard<std::mutex> lock(mInstanceMutex);
+    if(mInstance == nullptr)
+    {
+      mInstance = new TaskQueue();
+    }
+  }
+  return mInstance;
+}
+
+TaskQueue::TaskQueue()
+  : mIsThreadWaiting(true)
+{
+}
+
+void TaskQueue::AddTask(TaskCallback task)
+{
+  std::unique_lock<std::mutex> lock(mMutex);
+  mTaskQueue.push_back(task);
+}
+
+void TaskQueue::NotifyTaskReady()
+{
+  std::unique_lock<std::mutex> lock(mMutex);
+  mIsThreadWaiting = false;
+
+  // wake up the request interceptor thread
+  mCondition.notify_all();
+}
+
+void TaskQueue::WaitAndRunTasks()
+{
+  // wait for tasks.
+  std::unique_lock<std::mutex> lock(mMutex);
+  while(mIsThreadWaiting)
+  {
+    mCondition.wait(lock);
+  }
+  mIsThreadWaiting = true;
+
+  // execute tasks.
+  for(std::vector<TaskCallback>::iterator iter = mTaskQueue.begin(); iter != mTaskQueue.end(); iter++)
+  {
+    (*iter)();
+  }
+  mTaskQueue.clear();
+}
+
+} // namespace Plugin
+} // namespace Dali
diff --git a/dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.h b/dali-extension/web-engine-chromium/tizen-web-engine-request-interceptor-task-queue.h
new file mode 100755 (executable)
index 0000000..ce1c0ef
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef DALI_PLUGIN_TIZEN_WEB_ENGINE_REQUEST_INTERCEPTOR_TASK_QUEUE_H
+#define DALI_PLUGIN_TIZEN_WEB_ENGINE_REQUEST_INTERCEPTOR_TASK_QUEUE_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <atomic>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <vector>
+
+namespace Dali
+{
+namespace Plugin
+{
+
+/**
+ * @brief A class TaskQueue for running tasks. It is thread-safe.
+ */
+class TaskQueue
+{
+public:
+  static TaskQueue* GetInstance();
+
+  /**
+   * @brief Task callback.
+   */
+  using TaskCallback = std::function<bool(void)>;
+
+  /**
+   * @brief Add task.
+   */
+  void AddTask(TaskCallback taskQueue);
+
+  /**
+   * @brief Notify that tasks are ready.
+   */
+  void NotifyTaskReady();
+
+  /**
+   * @brief Wait for and run tasks.
+   */
+  void WaitAndRunTasks();
+
+private:
+  TaskQueue();
+
+  static std::atomic<TaskQueue*> mInstance;
+  static std::mutex              mInstanceMutex;
+
+  bool                      mIsThreadWaiting;
+  std::vector<TaskCallback> mTaskQueue;
+  std::mutex                mMutex;
+  std::condition_variable   mCondition;\r
+};
+
+} // namespace Plugin
+} // namespace Dali
+
+#endif // DALI_PLUGIN_TIZEN_WEB_ENGINE_REQUEST_INTERCEPTOR_TASK_QUEUE_H
index 4b0fa8ff184683d9601e991a17427d11d0090f72..fe1366d2518d61c463a633bf73a39d96a62e089c 100755 (executable)
@@ -16,6 +16,7 @@
  */
 
 #include "tizen-web-engine-request-interceptor.h"
+#include "tizen-web-engine-request-interceptor-task-queue.h"
 
 namespace Dali
 {
@@ -25,6 +26,11 @@ namespace Plugin
 TizenWebEngineRequestInterceptor::TizenWebEngineRequestInterceptor(Ewk_Intercept_Request* interceptor)
   : ewkRequestInterceptor(interceptor)
 {
+  const char* url = ewk_intercept_request_url_get(ewkRequestInterceptor);
+  if (url)
+  {
+    requestUrl = std::string(url);
+  }
 }
 
 TizenWebEngineRequestInterceptor::~TizenWebEngineRequestInterceptor()
@@ -33,26 +39,59 @@ TizenWebEngineRequestInterceptor::~TizenWebEngineRequestInterceptor()
 
 std::string TizenWebEngineRequestInterceptor::GetUrl() const
 {
-  const char* url = ewk_intercept_request_url_get(ewkRequestInterceptor);
-  return url ? std::string(url) : std::string();
+  return requestUrl;
 }
 
 bool TizenWebEngineRequestInterceptor::Ignore()
 {
-  return ewk_intercept_request_ignore(ewkRequestInterceptor);
+  TaskQueue::GetInstance()->AddTask(std::bind(&TizenWebEngineRequestInterceptor::IgnoreUi, this));
+  return true;
 }
 
 bool TizenWebEngineRequestInterceptor::SetResponseStatus(int statusCode, const std::string& customStatusText)
 {
-  return ewk_intercept_request_response_status_set(ewkRequestInterceptor, statusCode, customStatusText.c_str());
+  TaskQueue::GetInstance()->AddTask(std::bind(&TizenWebEngineRequestInterceptor::SetResponseStatusUi, this, statusCode, customStatusText));
+  return true;
 }
 
 bool TizenWebEngineRequestInterceptor::AddResponseHeader(const std::string& fieldName, const std::string& fieldValue)
 {
-  return ewk_intercept_request_response_header_add(ewkRequestInterceptor, fieldName.c_str(), fieldValue.c_str());
+  TaskQueue::GetInstance()->AddTask(std::bind(&TizenWebEngineRequestInterceptor::AddResponseHeaderUi, this, fieldName, fieldValue));
+  return true;
 }
 
 bool TizenWebEngineRequestInterceptor::AddResponseBody(const std::string& body, uint32_t length)
+{
+  TaskQueue::GetInstance()->AddTask(std::bind(&TizenWebEngineRequestInterceptor::AddResponseBodyUi, this, body, length));
+  return true;
+}
+
+void TizenWebEngineRequestInterceptor::WaitAndRunTasks()
+{
+  TaskQueue::GetInstance()->WaitAndRunTasks();
+}
+
+void TizenWebEngineRequestInterceptor::NotifyTaskReady()
+{
+  TaskQueue::GetInstance()->NotifyTaskReady();
+}
+
+bool TizenWebEngineRequestInterceptor::IgnoreUi()
+{
+  return ewk_intercept_request_ignore(ewkRequestInterceptor);
+}
+
+bool TizenWebEngineRequestInterceptor::SetResponseStatusUi(int statusCode, const std::string& customStatusText)
+{
+  return ewk_intercept_request_response_status_set(ewkRequestInterceptor, statusCode, customStatusText.c_str());
+}
+
+bool TizenWebEngineRequestInterceptor::AddResponseHeaderUi(const std::string& fieldName, const std::string& fieldValue)
+{
+  return ewk_intercept_request_response_header_add(ewkRequestInterceptor, fieldName.c_str(), fieldValue.c_str());
+}
+
+bool TizenWebEngineRequestInterceptor::AddResponseBodyUi(const std::string& body, uint32_t length)
 {
   return ewk_intercept_request_response_body_set(ewkRequestInterceptor, body.c_str(), length);
 }
index 083301be95251bf04d01b138cbabe73549746a10..ea58cadd2594d4d8b8c57fea59c33ce66d195ff4 100755 (executable)
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/web-engine-request-interceptor.h>
-#include <ewk_intercept_request.h>
+
+#include <functional>
 #include <string>
+#include <vector>
+
+#include <ewk_intercept_request.h>
 
 namespace Dali
 {
@@ -70,8 +74,44 @@ public:
    */
   bool AddResponseBody(const std::string& body, uint32_t length) override;
 
+  /**
+   * @brief Wait for and run tasks on ui-thread.
+   */
+  void WaitAndRunTasks();
+
+  /**
+   * @brief Notify task ready on main thread.
+   */
+  void NotifyTaskReady();
+
+private:
+  /**
+   * @copydoc Dali::WebEngineRequestInterceptor::Ignore()
+   * @note It is run on ui thread
+   */
+  bool IgnoreUi();
+
+  /**
+   * @copydoc Dali::WebEngineRequestInterceptor::SetResponseStatus()
+   * @note It is run on ui thread
+   */
+  bool SetResponseStatusUi(int statusCode, const std::string& customStatusText);
+
+  /**
+   * @copydoc Dali::WebEngineRequestInterceptor::AddResponseHeader()
+   * @note It is run on ui thread
+   */
+  bool AddResponseHeaderUi(const std::string& fieldName, const std::string& fieldValue);
+
+  /**
+   * @copydoc Dali::WebEngineRequestInterceptor::AddResponseBody()
+   * @note It is run on ui thread
+   */
+  bool AddResponseBodyUi(const std::string& body, uint32_t length);
+
 private:
   Ewk_Intercept_Request* ewkRequestInterceptor;
+  std::string            requestUrl;
 };
 
 } // namespace Plugin