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 "napi_web_cookie_manager.h"
17
18 #include <cstdint>
19 #include <uv.h>
20 #include <vector>
21
22 #include "business_error.h"
23 #include "napi/native_common.h"
24 #include "nweb_cookie_manager.h"
25 #include "nweb_helper.h"
26 #include "nweb_log.h"
27 #include "napi_parse_utils.h"
28 #include "web_errors.h"
29 #include "securec.h"
30
31 namespace OHOS {
32 namespace NWeb {
Init(napi_env env,napi_value exports)33 napi_value NapiWebCookieManager::Init(napi_env env, napi_value exports)
34 {
35 napi_property_descriptor properties[] = {
36 DECLARE_NAPI_STATIC_FUNCTION("getCookie", NapiWebCookieManager::JsGetCookie),
37 DECLARE_NAPI_STATIC_FUNCTION("setCookie", NapiWebCookieManager::JsSetCookie),
38 DECLARE_NAPI_STATIC_FUNCTION("isCookieAllowed", NapiWebCookieManager::JsIsCookieAllowed),
39 DECLARE_NAPI_STATIC_FUNCTION("putAcceptCookieEnabled", NapiWebCookieManager::JsPutAcceptCookieEnabled),
40 DECLARE_NAPI_STATIC_FUNCTION("isThirdPartyCookieAllowed",
41 NapiWebCookieManager::JsIsThirdPartyCookieAllowed),
42 DECLARE_NAPI_STATIC_FUNCTION("putAcceptThirdPartyCookieEnabled",
43 NapiWebCookieManager::JsPutAcceptThirdPartyCookieEnabled),
44 DECLARE_NAPI_STATIC_FUNCTION("existCookie", NapiWebCookieManager::JsExistCookie),
45 DECLARE_NAPI_STATIC_FUNCTION("deleteEntireCookie", NapiWebCookieManager::JsDeleteEntireCookie),
46 DECLARE_NAPI_STATIC_FUNCTION("deleteSessionCookie", NapiWebCookieManager::JsDeleteSessionCookie),
47 DECLARE_NAPI_STATIC_FUNCTION("saveCookieAsync", NapiWebCookieManager::JsSaveCookieAsync),
48 };
49 napi_value constructor = nullptr;
50
51 napi_define_class(env, WEB_COOKIE_MANAGER_CLASS_NAME.c_str(), WEB_COOKIE_MANAGER_CLASS_NAME.length(),
52 JsConstructor, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor);
53 NAPI_ASSERT(env, constructor != nullptr, "NapiWebCookieManager define js class failed");
54 napi_status status = napi_set_named_property(env, exports, "WebCookieManager", constructor);
55 NAPI_ASSERT(env, status == napi_ok, "NapiWebCookieManager set property failed");
56 return exports;
57 }
58
JsConstructor(napi_env env,napi_callback_info info)59 napi_value NapiWebCookieManager::JsConstructor(napi_env env, napi_callback_info info)
60 {
61 napi_value thisVar = nullptr;
62
63 size_t argc = INTEGER_TWO;
64 napi_value argv[INTEGER_TWO] = { 0 };
65 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
66 return thisVar;
67 }
68
GetStringPara(napi_env env,napi_value argv,std::string & outValue)69 bool NapiWebCookieManager::GetStringPara(napi_env env, napi_value argv, std::string& outValue)
70 {
71 constexpr int32_t MAX_STRING_LENGTH = 40960;
72 size_t bufferSize = 0;
73 napi_valuetype valueType = napi_null;
74
75 napi_typeof(env, argv, &valueType);
76 if (valueType != napi_string) {
77 return false;
78 }
79 napi_get_value_string_utf8(env, argv, nullptr, 0, &bufferSize);
80 if (bufferSize > MAX_STRING_LENGTH) {
81 return false;
82 }
83 char stringValue[bufferSize + 1];
84 size_t jsStringLength = 0;
85 napi_get_value_string_utf8(env, argv, stringValue, bufferSize + 1, &jsStringLength);
86 if (jsStringLength != bufferSize) {
87 return false;
88 }
89 outValue = stringValue;
90 return true;
91 }
92
GetBooleanPara(napi_env env,napi_value argv,bool & outValue)93 bool NapiWebCookieManager::GetBooleanPara(napi_env env, napi_value argv, bool& outValue)
94 {
95 napi_valuetype valueType = napi_null;
96
97 napi_typeof(env, argv, &valueType);
98 if (valueType != napi_boolean) {
99 return false;
100 }
101
102 bool boolValue;
103 napi_get_value_bool(env, argv, &boolValue);
104 outValue = boolValue;
105 return true;
106 }
107
JsGetCookie(napi_env env,napi_callback_info info)108 napi_value NapiWebCookieManager::JsGetCookie(napi_env env, napi_callback_info info)
109 {
110 napi_value retValue = nullptr;
111 size_t argc = INTEGER_ONE;
112 napi_value argv[INTEGER_ONE] = { 0 };
113
114 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
115 if (argc != INTEGER_ONE) {
116 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
117 return nullptr;
118 }
119
120 std::string url;
121 if (!GetStringPara(env, argv[INTEGER_ZERO], url)) {
122 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
123 return nullptr;
124 }
125
126 napi_value result = nullptr;
127 std::string cookieContent = "";
128
129 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
130 bool is_valid = true;
131 if (cookieManager != nullptr) {
132 cookieContent = cookieManager->ReturnCookie(url, is_valid);
133 }
134
135 if (cookieContent == "" && !is_valid) {
136 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_URL);
137 return nullptr;
138 }
139 napi_create_string_utf8(env, cookieContent.c_str(), cookieContent.length(), &result);
140 return result;
141 }
142
JsSetCookie(napi_env env,napi_callback_info info)143 napi_value NapiWebCookieManager::JsSetCookie(napi_env env, napi_callback_info info)
144 {
145 napi_value retValue = nullptr;
146 size_t argc = INTEGER_TWO;
147 napi_value argv[INTEGER_TWO] = { 0 };
148
149 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
150 if (argc != INTEGER_TWO) {
151 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
152 return nullptr;
153 }
154
155 std::string url;
156 std::string value;
157 if (!GetStringPara(env, argv[INTEGER_ZERO], url)) {
158 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
159 return nullptr;
160 }
161 if (!GetStringPara(env, argv[INTEGER_ONE], value)) {
162 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
163 return nullptr;
164 }
165
166 napi_value result = nullptr;
167 int isSet = -1;
168
169 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
170 if (cookieManager != nullptr) {
171 isSet = cookieManager->SetCookie(url, value);
172 }
173 if (isSet == NWebError::INVALID_URL) {
174 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_URL);
175 return nullptr;
176 } else if (isSet == NWebError::INVALID_COOKIE_VALUE) {
177 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_COOKIE_VALUE);
178 return nullptr;
179 }
180 NAPI_CALL(env, napi_get_undefined(env, &result));
181 return result;
182 }
183
JsIsCookieAllowed(napi_env env,napi_callback_info info)184 napi_value NapiWebCookieManager::JsIsCookieAllowed(napi_env env, napi_callback_info info)
185 {
186 napi_value result = nullptr;
187 bool accept = true;
188
189 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
190 if (cookieManager != nullptr) {
191 accept = cookieManager->IsAcceptCookieAllowed();
192 }
193 NAPI_CALL(env, napi_get_boolean(env, accept, &result));
194 return result;
195 }
196
JsPutAcceptCookieEnabled(napi_env env,napi_callback_info info)197 napi_value NapiWebCookieManager::JsPutAcceptCookieEnabled(napi_env env, napi_callback_info info)
198 {
199 napi_value retValue = nullptr;
200 size_t argc = INTEGER_ONE;
201 napi_value argv[INTEGER_ONE] = { 0 };
202
203 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
204 if (argc != INTEGER_ONE) {
205 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
206 return nullptr;
207 }
208
209 bool accept;
210 if (!GetBooleanPara(env, argv[INTEGER_ZERO], accept)) {
211 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
212 return nullptr;
213 }
214
215 napi_value result = nullptr;
216
217 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
218 if (cookieManager != nullptr) {
219 cookieManager->PutAcceptCookieEnabled(accept);
220 }
221 NAPI_CALL(env, napi_get_undefined(env, &result));
222 return result;
223 }
224
JsIsThirdPartyCookieAllowed(napi_env env,napi_callback_info info)225 napi_value NapiWebCookieManager::JsIsThirdPartyCookieAllowed(napi_env env, napi_callback_info info)
226 {
227 napi_value result = nullptr;
228 bool accept = true;
229
230 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
231 if (cookieManager != nullptr) {
232 accept = cookieManager->IsThirdPartyCookieAllowed();
233 }
234 NAPI_CALL(env, napi_get_boolean(env, accept, &result));
235 return result;
236 }
237
JsPutAcceptThirdPartyCookieEnabled(napi_env env,napi_callback_info info)238 napi_value NapiWebCookieManager::JsPutAcceptThirdPartyCookieEnabled(napi_env env, napi_callback_info info)
239 {
240 napi_value retValue = nullptr;
241 size_t argc = INTEGER_ONE;
242 napi_value argv[INTEGER_ONE] = { 0 };
243
244 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
245 if (argc != INTEGER_ONE) {
246 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
247 return nullptr;
248 }
249
250 bool accept;
251 if (!GetBooleanPara(env, argv[INTEGER_ZERO], accept)) {
252 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
253 return nullptr;
254 }
255
256 napi_value result = nullptr;
257
258 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
259 if (cookieManager != nullptr) {
260 cookieManager->PutAcceptThirdPartyCookieEnabled(accept);
261 }
262 NAPI_CALL(env, napi_get_undefined(env, &result));
263 return result;
264 }
265
JsExistCookie(napi_env env,napi_callback_info info)266 napi_value NapiWebCookieManager::JsExistCookie(napi_env env, napi_callback_info info)
267 {
268 napi_value result = nullptr;
269 bool exist = true;
270
271 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
272 if (cookieManager != nullptr) {
273 exist = cookieManager->ExistCookies();
274 }
275 NAPI_CALL(env, napi_get_boolean(env, exist, &result));
276 return result;
277 }
278
JsDeleteEntireCookie(napi_env env,napi_callback_info info)279 napi_value NapiWebCookieManager::JsDeleteEntireCookie(napi_env env, napi_callback_info info)
280 {
281 napi_value result = nullptr;
282
283 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
284 if (cookieManager != nullptr) {
285 cookieManager->DeleteCookieEntirely(nullptr);
286 }
287 NAPI_CALL(env, napi_get_undefined(env, &result));
288 return result;
289 }
290
JsDeleteSessionCookie(napi_env env,napi_callback_info info)291 napi_value NapiWebCookieManager::JsDeleteSessionCookie(napi_env env, napi_callback_info info)
292 {
293 napi_value result = nullptr;
294
295 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
296 if (cookieManager != nullptr) {
297 cookieManager->DeleteSessionCookies(nullptr);
298 }
299 napi_get_undefined(env, &result);
300 return result;
301 }
302
SaveCookieAsyncCallback(napi_env env,napi_ref jsCallback)303 void SaveCookieAsyncCallback(napi_env env, napi_ref jsCallback)
304 {
305 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
306 if (cookieManager == nullptr) {
307 napi_value jsResult = nullptr;
308 napi_get_null(env, &jsResult);
309 napi_value callback = nullptr;
310 napi_get_reference_value(env, jsCallback, &callback);
311 napi_value callbackResult = nullptr;
312 napi_call_function(env, nullptr, callback, INTEGER_ONE, &jsResult, &callbackResult);
313 napi_delete_reference(env, jsCallback);
314 } else {
315 auto callbackImpl = std::make_shared<OHOS::NWeb::NWebSaveCookieCallbackImpl>(env, jsCallback, nullptr);
316 cookieManager->Store(callbackImpl);
317 }
318 }
319
SaveCookieAsyncPromise(napi_env env,napi_deferred deferred)320 void SaveCookieAsyncPromise(napi_env env, napi_deferred deferred)
321 {
322 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
323 if (cookieManager == nullptr) {
324 napi_value jsResult = nullptr;
325 napi_get_undefined(env, &jsResult);
326 napi_reject_deferred(env, deferred, jsResult);
327 } else {
328 auto callbackImpl = std::make_shared<OHOS::NWeb::NWebSaveCookieCallbackImpl>(env, nullptr, deferred);
329 cookieManager->Store(callbackImpl);
330 }
331 }
332
JsSaveCookieAsync(napi_env env,napi_callback_info info)333 napi_value NapiWebCookieManager::JsSaveCookieAsync(napi_env env, napi_callback_info info)
334 {
335 napi_value thisVar = nullptr;
336
337 size_t argc = INTEGER_ONE;
338 size_t argcPromise = INTEGER_ZERO;
339 size_t argcCallback = INTEGER_ONE;
340 napi_value argv[INTEGER_ONE] = {0};
341
342 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
343 if (argc != argcPromise && argc != argcCallback) {
344 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
345 return nullptr;
346 }
347
348 napi_value result = nullptr;
349 napi_get_undefined(env, &result);
350
351 if (argc == argcCallback) {
352 napi_valuetype valueType = napi_null;
353 napi_typeof(env, argv[argcCallback - 1], &valueType);
354 if (valueType != napi_function) {
355 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
356 return nullptr;
357 }
358 napi_ref jsCallback = nullptr;
359 napi_create_reference(env, argv[argcCallback - 1], INTEGER_ONE, &jsCallback);
360
361 if (jsCallback) {
362 SaveCookieAsyncCallback(env, jsCallback);
363 }
364 return result;
365 }
366
367 napi_deferred deferred = nullptr;
368 napi_value promise = nullptr;
369 napi_create_promise(env, &deferred, &promise);
370 if (promise && deferred) {
371 SaveCookieAsyncPromise(env, deferred);
372 }
373 return promise;
374 }
375
UvJsCallbackThreadWoker(uv_work_t * work,int status)376 void NWebSaveCookieCallbackImpl::UvJsCallbackThreadWoker(uv_work_t *work, int status)
377 {
378 if (work == nullptr) {
379 WVLOG_E("uv work is null");
380 return;
381 }
382 NapiWebCookieManager::WebCookieManagerParam *data =
383 reinterpret_cast<NapiWebCookieManager::WebCookieManagerParam*>(work->data);
384 if (data == nullptr) {
385 WVLOG_E("WebCookieManagerParam is null");
386 delete work;
387 work = nullptr;
388 return;
389 }
390 napi_handle_scope scope = nullptr;
391 napi_open_handle_scope(data->env_, &scope);
392 if (scope == nullptr) {
393 return;
394 }
395
396 if (data->callback_) {
397 napi_value result[INTEGER_ONE] = {0};
398 napi_get_null(data->env_, &result[INTEGER_ZERO]);
399
400 napi_value onSaveCookieFunc = nullptr;
401 napi_get_reference_value(data->env_, data->callback_, &onSaveCookieFunc);
402 napi_value callbackResult = nullptr;
403 napi_call_function(data->env_, nullptr, onSaveCookieFunc,
404 INTEGER_ONE, &result[INTEGER_ZERO], &callbackResult);
405 napi_delete_reference(data->env_, data->callback_);
406 } else if (data->deferred_) {
407 napi_value jsResult = nullptr;
408 napi_get_undefined(data->env_, &jsResult);
409 napi_resolve_deferred(data->env_, data->deferred_, jsResult);
410 }
411
412 napi_close_handle_scope(data->env_, scope);
413 delete data;
414 data = nullptr;
415 delete work;
416 work = nullptr;
417 }
418
OnReceiveValue(bool result)419 void NWebSaveCookieCallbackImpl::OnReceiveValue(bool result)
420 {
421 WVLOG_D("save cookie received result, result = %{public}d", result);
422 uv_loop_s *loop = nullptr;
423 uv_work_t *work = nullptr;
424 napi_get_uv_event_loop(env_, &loop);
425 if (loop == nullptr) {
426 WVLOG_E("get uv event loop failed");
427 return;
428 }
429 work = new (std::nothrow) uv_work_t;
430 if (work == nullptr) {
431 WVLOG_E("new uv work failed");
432 return;
433 }
434 NapiWebCookieManager::WebCookieManagerParam *param =
435 new (std::nothrow) NapiWebCookieManager::WebCookieManagerParam();
436 if (param == nullptr) {
437 WVLOG_E("new WebCookieManagerParam failed");
438 delete work;
439 return;
440 }
441 param->env_ = env_;
442 param->callback_ = callback_;
443 param->deferred_ = deferred_;
444
445 work->data = reinterpret_cast<void*>(param);
446 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvJsCallbackThreadWoker);
447 if (ret != 0) {
448 if (param != nullptr) {
449 delete param;
450 param = nullptr;
451 }
452 if (work != nullptr) {
453 delete work;
454 work = nullptr;
455 }
456 }
457 }
458 } // namespace NWeb
459 } // namespace OHOS
460