• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "webview_javascript_execute_callback.h"
17 
18 #include "business_error.h"
19 #include "napi_parse_utils.h"
20 #include "nweb_log.h"
21 #include "web_errors.h"
22 
23 namespace OHOS::NWeb {
24 using namespace NWebError;
25 const std::string JS_EXCUTE_MSG_ENUM_NAME = "JsMessageType";
26 const std::string JS_EXT_MSG_CLASS_NAME = "JsMessageExt";
27 thread_local napi_ref g_jsMsgExtClassRef;
28 // static
InitJSExcute(napi_env env,napi_value exports)29 void WebviewJavaScriptExecuteCallback::InitJSExcute(napi_env env, napi_value exports)
30 {
31     napi_value jsMsgTypeEnum = nullptr;
32     napi_property_descriptor jsMsgTypeProperties[] = {
33         DECLARE_NAPI_STATIC_PROPERTY("NOT_SUPPORT", NapiParseUtils::ToInt32Value(env,
34             static_cast<int32_t>(JsMessageType::NOTSUPPORT))),
35         DECLARE_NAPI_STATIC_PROPERTY("STRING", NapiParseUtils::ToInt32Value(env,
36             static_cast<int32_t>(JsMessageType::STRING))),
37         DECLARE_NAPI_STATIC_PROPERTY("NUMBER", NapiParseUtils::ToInt32Value(env,
38             static_cast<int32_t>(JsMessageType::NUMBER))),
39         DECLARE_NAPI_STATIC_PROPERTY("BOOLEAN", NapiParseUtils::ToInt32Value(env,
40             static_cast<int32_t>(JsMessageType::BOOLEAN))),
41         DECLARE_NAPI_STATIC_PROPERTY("ARRAY_BUFFER", NapiParseUtils::ToInt32Value(env,
42             static_cast<int32_t>(JsMessageType::ARRAYBUFFER))),
43         DECLARE_NAPI_STATIC_PROPERTY("ARRAY", NapiParseUtils::ToInt32Value(env,
44             static_cast<int32_t>(JsMessageType::ARRAY)))
45     };
46     napi_define_class(env, JS_EXCUTE_MSG_ENUM_NAME.c_str(), JS_EXCUTE_MSG_ENUM_NAME.length(),
47         NapiParseUtils::CreateEnumConstructor, nullptr, sizeof(jsMsgTypeProperties) /
48         sizeof(jsMsgTypeProperties[0]), jsMsgTypeProperties, &jsMsgTypeEnum);
49     napi_set_named_property(env, exports, JS_EXCUTE_MSG_ENUM_NAME.c_str(), jsMsgTypeEnum);
50 
51     napi_value jsMsgExtClass = nullptr;
52     napi_property_descriptor jsMsgExtClsProperties[] = {
53         DECLARE_NAPI_FUNCTION("getType", NapiJsMessageExt::GetType),
54         DECLARE_NAPI_FUNCTION("getString", NapiJsMessageExt::GetString),
55         DECLARE_NAPI_FUNCTION("getNumber", NapiJsMessageExt::GetNumber),
56         DECLARE_NAPI_FUNCTION("getBoolean", NapiJsMessageExt::GetBoolean),
57         DECLARE_NAPI_FUNCTION("getArrayBuffer", NapiJsMessageExt::GetArrayBuffer),
58         DECLARE_NAPI_FUNCTION("getArray", NapiJsMessageExt::GetArray)
59     };
60     napi_define_class(env, JS_EXT_MSG_CLASS_NAME.c_str(), JS_EXT_MSG_CLASS_NAME.length(),
61         NapiJsMessageExt::JsConstructor, nullptr, sizeof(jsMsgExtClsProperties) / sizeof(jsMsgExtClsProperties[0]),
62         jsMsgExtClsProperties, &jsMsgExtClass);
63     napi_create_reference(env, jsMsgExtClass, 1, &g_jsMsgExtClassRef);
64     napi_set_named_property(env, exports, JS_EXT_MSG_CLASS_NAME.c_str(), jsMsgExtClass);
65 }
66 
OnReceiveValue(std::shared_ptr<NWebMessage> result)67 void WebviewJavaScriptExecuteCallback::OnReceiveValue(std::shared_ptr<NWebMessage> result)
68 {
69     WVLOG_D("WebviewJavaScriptExecuteCallback::OnReceiveValue start");
70     uv_loop_s *loop = nullptr;
71     uv_work_t *work = nullptr;
72 
73     napi_get_uv_event_loop(env_, &loop);
74     if (loop == nullptr) {
75         return;
76     }
77     work = new (std::nothrow) uv_work_t;
78     if (work == nullptr) {
79         return;
80     }
81 
82     JavaScriptExecuteParam *param = new (std::nothrow) JavaScriptExecuteParam();
83     if (param == nullptr) {
84         delete work;
85         return;
86     }
87     param->env_ = env_;
88     param->callbackRef_ = callbackRef_;
89     param->deferred_ = deferred_;
90     param->result_ = result;
91     param->extention_ = extention_;
92 
93     work->data = reinterpret_cast<void*>(param);
94 
95     int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvAfterWorkCb);
96     if (ret != 0) {
97         if (param != nullptr) {
98             delete param;
99             param = nullptr;
100         }
101         if (work != nullptr) {
102             delete work;
103             work = nullptr;
104         }
105     }
106 }
107 
UvAfterWorkCb(uv_work_t * work,int status)108 void WebviewJavaScriptExecuteCallback::UvAfterWorkCb(uv_work_t* work, int status)
109 {
110     WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCb");
111     (void)status;
112     if (!work) {
113         return;
114     }
115     JavaScriptExecuteParam *param = reinterpret_cast<JavaScriptExecuteParam*>(work->data);
116     if (!param) {
117         delete work;
118         work = nullptr;
119         return;
120     }
121     napi_handle_scope scope = nullptr;
122     napi_open_handle_scope(param->env_, &scope);
123     if (scope == nullptr) {
124         return;
125     }
126 
127     if (param->callbackRef_) {
128         UvAfterWorkCbAsync(param->env_, param->callbackRef_, param->result_, param->extention_);
129     } else if (param->deferred_) {
130         UvAfterWorkCbPromise(param->env_, param->deferred_, param->result_, param->extention_);
131     }
132 
133     napi_close_handle_scope(param->env_, scope);
134     delete param;
135     param = nullptr;
136     delete work;
137     work = nullptr;
138 }
139 
UvAfterWorkCbAsync(napi_env env,napi_ref callbackRef,std::shared_ptr<NWebMessage> result,bool extention)140 void WebviewJavaScriptExecuteCallback::UvAfterWorkCbAsync(napi_env env, napi_ref callbackRef,
141     std::shared_ptr<NWebMessage> result, bool extention)
142 {
143     WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCbAsync");
144     napi_value setResult[INTEGER_TWO] = {0};
145     if (result->GetType() == NWebValue::Type::STRING && result->GetString().empty()) {
146         setResult[INTEGER_ZERO] = BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
147         napi_get_null(env, &setResult[INTEGER_ONE]);
148     } else {
149         napi_get_undefined(env, &setResult[INTEGER_ZERO]);
150         if (!extention) {
151             OHOS::NWeb::NapiParseUtils::ConvertNWebToNapiValue(env, result, setResult[INTEGER_ONE]);
152         } else {
153             napi_value jsMsgExt = nullptr;
154             NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, g_jsMsgExtClassRef, &jsMsgExt));
155             NAPI_CALL_RETURN_VOID(env, napi_new_instance(env, jsMsgExt, 0, NULL, &setResult[INTEGER_ONE]));
156 
157             WebJsMessageExt *webJsMessageExt = new (std::nothrow) WebJsMessageExt(result);
158             if (webJsMessageExt == nullptr) {
159                 WVLOG_E("new WebJsMessageExt failed.");
160                 return;
161             }
162 
163             napi_status status = napi_wrap(env, setResult[INTEGER_ONE], webJsMessageExt,
164                 [](napi_env env, void *data, void *hint) {
165                     WebJsMessageExt *webJsMessageExt = static_cast<WebJsMessageExt *>(data);
166                     delete webJsMessageExt;
167                     webJsMessageExt = nullptr;
168                 },
169                 nullptr, nullptr);
170             if (status != napi_status::napi_ok) {
171                 WVLOG_E("napi_wrap failed");
172                 return;
173             }
174         }
175     }
176     napi_value args[INTEGER_TWO] = {setResult[INTEGER_ZERO], setResult[INTEGER_ONE]};
177     napi_value callback = nullptr;
178     napi_value callbackResult = nullptr;
179 
180     napi_get_reference_value(env, callbackRef, &callback);
181     napi_call_function(env, nullptr, callback, INTEGER_TWO, args, &callbackResult);
182     napi_delete_reference(env, callbackRef);
183 }
184 
UvAfterWorkCbPromise(napi_env env,napi_deferred deferred,std::shared_ptr<NWebMessage> result,bool extention)185 void WebviewJavaScriptExecuteCallback::UvAfterWorkCbPromise(napi_env env, napi_deferred deferred,
186     std::shared_ptr<NWebMessage> result, bool extention)
187 {
188     WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCbPromise");
189     napi_value setResult[INTEGER_TWO] = {0};
190     setResult[INTEGER_ZERO] = NWebError::BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
191     if (!extention) {
192         OHOS::NWeb::NapiParseUtils::ConvertNWebToNapiValue(env, result, setResult[INTEGER_ONE]);
193     } else {
194         napi_value jsMsgExt = nullptr;
195         napi_status status = napi_get_reference_value(env, g_jsMsgExtClassRef, &jsMsgExt);
196         if (status != napi_status::napi_ok) {
197             WVLOG_E("napi_get_reference_value failed.");
198             return;
199         }
200         status = napi_new_instance(env, jsMsgExt, 0, NULL, &setResult[INTEGER_ONE]);
201         if (status != napi_status::napi_ok) {
202             WVLOG_E("napi_new_instance failed.");
203             return;
204         }
205         WebJsMessageExt *webJsMessageExt = new (std::nothrow) WebJsMessageExt(result);
206         if (webJsMessageExt == nullptr) {
207             WVLOG_E("new WebJsMessageExt failed.");
208             return;
209         }
210 
211         status = napi_wrap(env, setResult[INTEGER_ONE], webJsMessageExt,
212             [](napi_env env, void *data, void *hint) {
213                 WebJsMessageExt *webJsMessageExt = static_cast<WebJsMessageExt *>(data);
214                 delete webJsMessageExt;
215                 webJsMessageExt = nullptr;
216             },
217             nullptr, nullptr);
218         if (status != napi_status::napi_ok) {
219             WVLOG_E("napi_wrap failed.");
220             return;
221         }
222     }
223 
224     napi_value args[INTEGER_TWO] = {setResult[INTEGER_ZERO], setResult[INTEGER_ONE]};
225     if (result->GetType() == NWebValue::Type::STRING && result->GetString().empty()) {
226         napi_reject_deferred(env, deferred, args[INTEGER_ZERO]);
227     } else {
228         napi_resolve_deferred(env, deferred, args[INTEGER_ONE]);
229     }
230 }
231 
JsConstructor(napi_env env,napi_callback_info info)232 napi_value NapiJsMessageExt::JsConstructor(napi_env env, napi_callback_info info)
233 {
234     napi_value thisVar = nullptr;
235     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
236     return thisVar;
237 }
238 
ConvertToJsType(NWebValue::Type type)239 int32_t WebJsMessageExt::ConvertToJsType(NWebValue::Type type)
240 {
241     JsMessageType jsMessageType = JsMessageType::NOTSUPPORT;
242     switch (type) {
243         case NWebValue::Type::STRING:
244             jsMessageType = JsMessageType::STRING;
245             break;
246         case NWebValue::Type::INTEGER:
247         case NWebValue::Type::DOUBLE:
248             jsMessageType = JsMessageType::NUMBER;
249             break;
250         case NWebValue::Type::BOOLEAN:
251             jsMessageType = JsMessageType::BOOLEAN;
252             break;
253         case NWebValue::Type::BINARY:
254             jsMessageType = JsMessageType::ARRAYBUFFER;
255             break;
256         case NWebValue::Type::STRINGARRAY:
257         case NWebValue::Type::BOOLEANARRAY:
258         case NWebValue::Type::DOUBLEARRAY:
259         case NWebValue::Type::INT64ARRAY:
260             jsMessageType = JsMessageType::ARRAY;
261             break;
262         default:
263             jsMessageType = JsMessageType::NOTSUPPORT;
264             break;
265     }
266     return static_cast<int32_t>(jsMessageType);
267 }
268 
GetType()269 int32_t WebJsMessageExt::GetType()
270 {
271     if (value_) {
272         return ConvertToJsType(value_->GetType());
273     }
274     return static_cast<int32_t>(JsMessageType::NOTSUPPORT);
275 }
276 
GetString()277 std::string WebJsMessageExt::GetString()
278 {
279     if (value_) {
280         return value_->GetString();
281     }
282     return "";
283 }
284 
GetNumber()285 double WebJsMessageExt::GetNumber()
286 {
287     if (value_) {
288         return value_->GetDouble();
289     }
290     return 0;
291 }
292 
GetBoolean()293 bool WebJsMessageExt::GetBoolean()
294 {
295     if (value_) {
296         return value_->GetBoolean();
297     }
298     return false;
299 }
300 
GetType(napi_env env,napi_callback_info info)301 napi_value NapiJsMessageExt::GetType(napi_env env, napi_callback_info info)
302 {
303     WVLOG_D("GetType webJsMessageExt start");
304     napi_value thisVar = nullptr;
305     napi_value result = nullptr;
306     size_t argc = INTEGER_ONE;
307     napi_value argv[INTEGER_ONE] = { 0 };
308 
309     WebJsMessageExt *webJsMessageExt = nullptr;
310     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
311     if (status != napi_status::napi_ok) {
312         WVLOG_E("napi_get_cb_info failed.");
313         return result;
314     }
315     status = napi_unwrap(env, thisVar, (void **)&webJsMessageExt);
316     if (status != napi_status::napi_ok) {
317         WVLOG_E("napi_unwrap failed.");
318         return result;
319     }
320     if (webJsMessageExt == nullptr) {
321         WVLOG_E("unwrap webJsMessageExt failed.");
322         return result;
323     }
324 
325     int32_t type = webJsMessageExt->GetType();
326     status = napi_create_int32(env, type, &result);
327     if (status != napi_status::napi_ok) {
328         WVLOG_E("napi_create_int32 failed.");
329         return result;
330     }
331     return result;
332 }
333 
GetString(napi_env env,napi_callback_info info)334 napi_value NapiJsMessageExt::GetString(napi_env env, napi_callback_info info)
335 {
336     WVLOG_D("GetString webJsMessageExt");
337     napi_value thisVar = nullptr;
338     napi_value result = nullptr;
339     size_t argc = INTEGER_ONE;
340     napi_value argv[INTEGER_ONE] = { 0 };
341 
342     WebJsMessageExt *webJsMessageExt = nullptr;
343     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
344     NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
345     if (webJsMessageExt == nullptr) {
346         WVLOG_E("unwrap webJsMessageExt failed.");
347         return result;
348     }
349 
350     if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::STRING)) {
351         BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
352         return nullptr;
353     }
354 
355     NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
356     return result;
357 }
358 
GetNumber(napi_env env,napi_callback_info info)359 napi_value NapiJsMessageExt::GetNumber(napi_env env, napi_callback_info info)
360 {
361     WVLOG_D("GetNumber webJsMessageExt");
362     napi_value thisVar = nullptr;
363     napi_value result = nullptr;
364     size_t argc = INTEGER_ONE;
365     napi_value argv[INTEGER_ONE] = { 0 };
366 
367     WebJsMessageExt *webJsMessageExt = nullptr;
368     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
369     NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
370     if (webJsMessageExt == nullptr) {
371         WVLOG_E("unwrap webJsMessageExt failed.");
372         return result;
373     }
374 
375     if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::NUMBER)) {
376         BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
377         WVLOG_E("GetNumber webJsMessageExt failed not match");
378         return nullptr;
379     }
380 
381     NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
382     return result;
383 }
384 
GetBoolean(napi_env env,napi_callback_info info)385 napi_value NapiJsMessageExt::GetBoolean(napi_env env, napi_callback_info info)
386 {
387     napi_value thisVar = nullptr;
388     napi_value result = nullptr;
389     size_t argc = INTEGER_ONE;
390     napi_value argv[INTEGER_ONE] = { 0 };
391 
392     WebJsMessageExt *webJsMessageExt = nullptr;
393     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
394     NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
395     if (webJsMessageExt == nullptr) {
396         WVLOG_E("unwrap webJsMessageExt failed.");
397         return result;
398     }
399 
400     if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::BOOLEAN)) {
401         BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
402         return nullptr;
403     }
404 
405     NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
406     return result;
407 }
408 
GetArrayBuffer(napi_env env,napi_callback_info info)409 napi_value NapiJsMessageExt::GetArrayBuffer(napi_env env, napi_callback_info info)
410 {
411     napi_value thisVar = nullptr;
412     napi_value result = nullptr;
413     size_t argc = INTEGER_ONE;
414     napi_value argv[INTEGER_ONE] = { 0 };
415 
416     WebJsMessageExt *webJsMessageExt = nullptr;
417     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
418     NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
419     if (webJsMessageExt == nullptr) {
420         WVLOG_E("unwrap webJsMessageExt failed.");
421         return result;
422     }
423 
424     if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::ARRAYBUFFER)) {
425         BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
426         return nullptr;
427     }
428     NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
429     return result;
430 }
431 
GetArray(napi_env env,napi_callback_info info)432 napi_value NapiJsMessageExt::GetArray(napi_env env, napi_callback_info info)
433 {
434     napi_value thisVar = nullptr;
435     napi_value result = nullptr;
436     size_t argc = INTEGER_ONE;
437     napi_value argv[INTEGER_ONE] = { 0 };
438 
439     WebJsMessageExt *webJsMessageExt = nullptr;
440     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
441     NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
442     if (webJsMessageExt == nullptr) {
443         WVLOG_E("unwrap webJsMessageExt failed.");
444         return result;
445     }
446 
447     if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::ARRAY)) {
448         BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
449         return nullptr;
450     }
451 
452     NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
453     return result;
454 }
455 
456 } // namespace OHOS::NWeb
457