• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "js_task.h"
17 
18 #include <securec.h>
19 #include <sys/stat.h>
20 
21 #include <chrono>
22 #include <cstring>
23 #include <filesystem>
24 #include <mutex>
25 
26 #include "app_state_callback.h"
27 #include "async_call.h"
28 #include "js_initialize.h"
29 #include "legacy/request_manager.h"
30 #include "log.h"
31 #include "napi_base_context.h"
32 #include "napi_utils.h"
33 #include "request_event.h"
34 #include "request_manager.h"
35 #include "storage_acl.h"
36 #include "upload/upload_task_napiV5.h"
37 
38 using namespace OHOS::StorageDaemon;
39 namespace fs = std::filesystem;
40 namespace OHOS::Request {
41 constexpr int64_t MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
42 std::mutex JsTask::createMutex_;
43 thread_local napi_ref JsTask::createCtor = nullptr;
44 std::mutex JsTask::requestMutex_;
45 thread_local napi_ref JsTask::requestCtor = nullptr;
46 std::mutex JsTask::requestFileMutex_;
47 thread_local napi_ref JsTask::requestFileCtor = nullptr;
48 std::mutex JsTask::getTaskCreateMutex_;
49 thread_local napi_ref JsTask::getTaskCreateCtor = nullptr;
50 std::mutex JsTask::taskMutex_;
51 std::map<std::string, JsTask *> JsTask::taskMap_;
52 bool JsTask::register_ = false;
53 std::mutex JsTask::pathMutex_;
54 std::map<std::string, int32_t> JsTask::pathMap_;
55 std::mutex JsTask::taskContextMutex_;
56 std::map<std::string, std::shared_ptr<JsTask::ContextInfo>> JsTask::taskContextMap_;
57 
58 napi_property_descriptor clzDes[] = {
59     DECLARE_NAPI_FUNCTION(FUNCTION_ON, RequestEvent::On),
60     DECLARE_NAPI_FUNCTION(FUNCTION_OFF, RequestEvent::Off),
61     DECLARE_NAPI_FUNCTION(FUNCTION_START, RequestEvent::Start),
62     DECLARE_NAPI_FUNCTION(FUNCTION_PAUSE, RequestEvent::Pause),
63     DECLARE_NAPI_FUNCTION(FUNCTION_RESUME, RequestEvent::Resume),
64     DECLARE_NAPI_FUNCTION(FUNCTION_STOP, RequestEvent::Stop),
65 };
66 
67 napi_property_descriptor clzDesV9[] = {
68     DECLARE_NAPI_FUNCTION(FUNCTION_ON, RequestEvent::On),
69     DECLARE_NAPI_FUNCTION(FUNCTION_OFF, RequestEvent::Off),
70     DECLARE_NAPI_FUNCTION(FUNCTION_SUSPEND, RequestEvent::Pause),
71     DECLARE_NAPI_FUNCTION(FUNCTION_GET_TASK_INFO, RequestEvent::Query),
72     DECLARE_NAPI_FUNCTION(FUNCTION_GET_TASK_MIME_TYPE, RequestEvent::QueryMimeType),
73     DECLARE_NAPI_FUNCTION(FUNCTION_DELETE, RequestEvent::Remove),
74     DECLARE_NAPI_FUNCTION(FUNCTION_RESTORE, RequestEvent::Resume),
75     DECLARE_NAPI_FUNCTION(FUNCTION_PAUSE, RequestEvent::Pause),
76     DECLARE_NAPI_FUNCTION(FUNCTION_QUERY, RequestEvent::Query),
77     DECLARE_NAPI_FUNCTION(FUNCTION_QUERY_MIME_TYPE, RequestEvent::QueryMimeType),
78     DECLARE_NAPI_FUNCTION(FUNCTION_REMOVE, RequestEvent::Remove),
79     DECLARE_NAPI_FUNCTION(FUNCTION_RESUME, RequestEvent::Resume),
80 };
81 
~JsTask()82 JsTask::~JsTask()
83 {
84     REQUEST_HILOGD("~JsTask()");
85     ClearListener();
86 }
JsUpload(napi_env env,napi_callback_info info)87 napi_value JsTask::JsUpload(napi_env env, napi_callback_info info)
88 {
89     REQUEST_HILOGD("JsUpload in");
90     std::shared_ptr<Upload::UploadTaskNapiV5> proxy = std::make_shared<Upload::UploadTaskNapiV5>(env);
91     if (proxy->ParseCallback(env, info)) {
92         return proxy->JsUpload(env, info);
93     }
94     proxy->SetEnv(nullptr);
95     return JsMain(env, info, Version::API8);
96 }
97 
JsDownload(napi_env env,napi_callback_info info)98 napi_value JsTask::JsDownload(napi_env env, napi_callback_info info)
99 {
100     REQUEST_HILOGD("JsDownload in");
101     if (Legacy::RequestManager::IsLegacy(env, info)) {
102         return Legacy::RequestManager::Download(env, info);
103     }
104     return JsMain(env, info, Version::API8);
105 }
106 
JsRequestFile(napi_env env,napi_callback_info info)107 napi_value JsTask::JsRequestFile(napi_env env, napi_callback_info info)
108 {
109     REQUEST_HILOGD("JsRequestFile in");
110     return JsMain(env, info, Version::API9);
111 }
112 
JsCreate(napi_env env,napi_callback_info info)113 napi_value JsTask::JsCreate(napi_env env, napi_callback_info info)
114 {
115     REQUEST_HILOGD("JsCreate in");
116     return JsMain(env, info, Version::API10);
117 }
118 
JsMain(napi_env env,napi_callback_info info,Version version)119 napi_value JsTask::JsMain(napi_env env, napi_callback_info info, Version version)
120 {
121     auto context = std::make_shared<ContextInfo>();
122     context->withErrCode_ = version != Version::API8;
123     context->version_ = version;
124     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
125         if (context->version_ == Version::API10) {
126             napi_create_reference(context->env_, argv[1], 1, &(context->jsConfig));
127         }
128         napi_value ctor = GetCtor(context->env_, context->version_);
129         napi_value jsTask = nullptr;
130         napi_status status = napi_new_instance(context->env_, ctor, argc, argv, &jsTask);
131         if (jsTask == nullptr || status != napi_ok) {
132             REQUEST_HILOGE("Get jsTask failed");
133             return napi_generic_failure;
134         }
135         napi_unwrap(context->env_, jsTask, reinterpret_cast<void **>(&context->task));
136         napi_create_reference(context->env_, jsTask, 1, &(context->taskRef));
137         return napi_ok;
138     };
139     auto exec = [context]() {
140         Config config = context->task->config_;
141         context->innerCode_ = CreateExec(context);
142         if (context->innerCode_ == E_SERVICE_ERROR && config.version == Version::API9
143             && config.action == Action::UPLOAD) {
144             context->withErrCode_ = false;
145         }
146     };
147     auto output = [context](napi_value *result) -> napi_status {
148         if (result == nullptr || context->innerCode_ != E_OK) {
149             return napi_generic_failure;
150         }
151         napi_status status = napi_get_reference_value(context->env_, context->taskRef, result);
152         context->task->SetTid(context->tid);
153         JsTask::AddTaskMap(std::to_string(context->tid), context->task);
154         JsTask::AddTaskContextMap(std::to_string(context->tid), context);
155         napi_value config = nullptr;
156         napi_get_reference_value(context->env_, context->jsConfig, &config);
157         JsInitialize::CreatProperties(context->env_, *result, config, context->task);
158         REQUEST_HILOGD("JsMain output");
159         return status;
160     };
161     context->SetInput(input).SetOutput(output).SetExec(exec);
162     AsyncCall asyncCall(env, info, context);
163     asyncCall.SetQosLevel(napi_qos_utility);
164     return asyncCall.Call(context, "create");
165 }
166 
CreateExec(const std::shared_ptr<ContextInfo> & context)167 int32_t JsTask::CreateExec(const std::shared_ptr<ContextInfo> &context)
168 {
169     if (!RequestManager::GetInstance()->LoadRequestServer()) {
170         return E_SERVICE_ERROR;
171     }
172     if (context->task->config_.mode == Mode::FOREGROUND) {
173         RegisterForegroundResume();
174     }
175     sptr<RequestNotify> listener = new RequestNotify();
176     std::string key = "done" + context->task->GetTid();
177     context->task->AddListener(key, listener);
178     return RequestManager::GetInstance()->Create(context->task->config_, context->tid, listener);
179 }
180 
GetCtor(napi_env env,Version version)181 napi_value JsTask::GetCtor(napi_env env, Version version)
182 {
183     switch (version) {
184         case Version::API8:
185             return GetCtorV8(env);
186         case Version::API9:
187             return GetCtorV9(env);
188         case Version::API10:
189             return GetCtorV10(env);
190         default:
191             break;
192     }
193     return nullptr;
194 }
195 
GetCtorV10(napi_env env)196 napi_value JsTask::GetCtorV10(napi_env env)
197 {
198     REQUEST_HILOGD("GetCtorV10 in");
199     std::lock_guard<std::mutex> lock(createMutex_);
200     napi_value cons;
201     if (createCtor != nullptr) {
202         NAPI_CALL(env, napi_get_reference_value(env, createCtor, &cons));
203         return cons;
204     }
205     size_t count = sizeof(clzDes) / sizeof(napi_property_descriptor);
206     return DefineClass(env, clzDes, count, Create, &createCtor);
207 }
208 
GetCtorV9(napi_env env)209 napi_value JsTask::GetCtorV9(napi_env env)
210 {
211     REQUEST_HILOGD("GetCtorV9 in");
212     std::lock_guard<std::mutex> lock(requestFileMutex_);
213     napi_value cons;
214     if (requestFileCtor != nullptr) {
215         NAPI_CALL(env, napi_get_reference_value(env, requestFileCtor, &cons));
216         return cons;
217     }
218     size_t count = sizeof(clzDesV9) / sizeof(napi_property_descriptor);
219     return DefineClass(env, clzDesV9, count, RequestFile, &requestFileCtor);
220 }
221 
GetCtorV8(napi_env env)222 napi_value JsTask::GetCtorV8(napi_env env)
223 {
224     REQUEST_HILOGD("GetCtorV8 in");
225     std::lock_guard<std::mutex> lock(requestMutex_);
226     napi_value cons;
227     if (requestCtor != nullptr) {
228         NAPI_CALL(env, napi_get_reference_value(env, requestCtor, &cons));
229         return cons;
230     }
231     size_t count = sizeof(clzDesV9) / sizeof(napi_property_descriptor);
232     return DefineClass(env, clzDesV9, count, RequestFileV8, &requestCtor);
233 }
234 
DefineClass(napi_env env,const napi_property_descriptor * desc,size_t count,napi_callback cb,napi_ref * ctor)235 napi_value JsTask::DefineClass(
236     napi_env env, const napi_property_descriptor *desc, size_t count, napi_callback cb, napi_ref *ctor)
237 {
238     napi_value cons = nullptr;
239     napi_status status = napi_define_class(env, "Request", NAPI_AUTO_LENGTH, cb, nullptr, count, desc, &cons);
240     if (status != napi_ok) {
241         REQUEST_HILOGE("napi_define_class failed");
242         return nullptr;
243     }
244     status = napi_create_reference(env, cons, 1, ctor);
245     if (status != napi_ok) {
246         REQUEST_HILOGE("napi_create_reference failed");
247         return nullptr;
248     }
249     return cons;
250 }
251 
Create(napi_env env,napi_callback_info info)252 napi_value JsTask::Create(napi_env env, napi_callback_info info)
253 {
254     REQUEST_HILOGD("Create API10");
255     return JsInitialize::Initialize(env, info, Version::API10);
256 }
257 
RequestFile(napi_env env,napi_callback_info info)258 napi_value JsTask::RequestFile(napi_env env, napi_callback_info info)
259 {
260     REQUEST_HILOGD("RequestFile API9");
261     return JsInitialize::Initialize(env, info, Version::API9);
262 }
263 
RequestFileV8(napi_env env,napi_callback_info info)264 napi_value JsTask::RequestFileV8(napi_env env, napi_callback_info info)
265 {
266     REQUEST_HILOGD("Request API8");
267     return JsInitialize::Initialize(env, info, Version::API8);
268 }
269 
GetTaskCtor(napi_env env)270 napi_value JsTask::GetTaskCtor(napi_env env)
271 {
272     REQUEST_HILOGD("GetTaskCtor in");
273     std::lock_guard<std::mutex> lock(getTaskCreateMutex_);
274     napi_value cons;
275     if (getTaskCreateCtor != nullptr) {
276         NAPI_CALL(env, napi_get_reference_value(env, getTaskCreateCtor, &cons));
277         return cons;
278     }
279     size_t count = sizeof(clzDes) / sizeof(napi_property_descriptor);
280     return DefineClass(env, clzDes, count, GetTaskCreate, &getTaskCreateCtor);
281 }
282 
GetTaskCreate(napi_env env,napi_callback_info info)283 napi_value JsTask::GetTaskCreate(napi_env env, napi_callback_info info)
284 {
285     REQUEST_HILOGD("GetTask Create");
286     return JsInitialize::Initialize(env, info, Version::API10, false);
287 }
288 
GetTask(napi_env env,napi_callback_info info)289 napi_value JsTask::GetTask(napi_env env, napi_callback_info info)
290 {
291     auto context = std::make_shared<ContextInfo>();
292     context->withErrCode_ = true;
293     context->version_ = Version::API10;
294     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
295         if (!ParseGetTask(context->env_, argc, argv, context)) {
296             NapiUtils::ThrowError(context->env_, E_PARAMETER_CHECK, "Parse tid or token fail!", true);
297             return napi_invalid_arg;
298         }
299         napi_create_reference(context->env_, argv[0], 1, &(context->baseContext));
300         return napi_ok;
301     };
302     auto output = [context](napi_value *result) -> napi_status {
303         if (context->innerCode_ != E_OK) {
304             return napi_generic_failure;
305         }
306         if (!GetTaskOutput(context)) {
307             return napi_generic_failure;
308         }
309         napi_status res = napi_get_reference_value(context->env_, context->taskRef, result);
310         context->task->SetTid(context->tid);
311         napi_value conf = nullptr;
312         napi_get_reference_value(context->env_, context->jsConfig, &conf);
313         JsInitialize::CreatProperties(context->env_, *result, conf, context->task);
314         return res;
315     };
316     auto exec = [context]() {
317         if (!RequestManager::GetInstance()->LoadRequestServer()) {
318             context->innerCode_ = E_SERVICE_ERROR;
319             return;
320         }
321         GetTaskExecution(context);
322     };
323     context->SetInput(input).SetOutput(output).SetExec(exec);
324     AsyncCall asyncCall(env, info, context);
325     return asyncCall.Call(context, "getTask");
326 }
327 
GetTaskExecution(std::shared_ptr<ContextInfo> context)328 void JsTask::GetTaskExecution(std::shared_ptr<ContextInfo> context)
329 {
330     std::string tid = std::to_string(context->tid);
331     if (taskContextMap_.find(tid) != taskContextMap_.end()) {
332         REQUEST_HILOGD("Find in taskContextMap_");
333         if (taskContextMap_[tid]->task->config_.version != Version::API10
334             || taskContextMap_[tid]->task->config_.token != context->token) {
335             context->innerCode_ = E_TASK_NOT_FOUND;
336             return;
337         }
338         context->task = taskContextMap_[tid]->task;
339         context->taskRef = taskContextMap_[tid]->taskRef;
340         context->jsConfig = taskContextMap_[tid]->jsConfig;
341         context->innerCode_ = E_OK;
342         return;
343     } else {
344         context->innerCode_ = RequestManager::GetInstance()->GetTask(tid, context->token, context->config);
345     }
346     if (context->config.version != Version::API10) {
347         context->innerCode_ = E_TASK_NOT_FOUND;
348     }
349 }
350 
GetTaskOutput(std::shared_ptr<ContextInfo> context)351 bool JsTask::GetTaskOutput(std::shared_ptr<ContextInfo> context)
352 {
353     std::string tid = std::to_string(context->tid);
354     if (taskMap_.find(tid) == taskMap_.end()) {
355         napi_value config = NapiUtils::Convert2JSValue(context->env_, context->config);
356         napi_create_reference(context->env_, config, 1, &(context->jsConfig));
357         napi_value ctor = GetTaskCtor(context->env_);
358         napi_value jsTask = nullptr;
359         napi_value baseCtx = nullptr;
360         napi_get_reference_value(context->env_, context->baseContext, &baseCtx);
361         napi_value args[2] = { baseCtx, config };
362         napi_status status = napi_new_instance(context->env_, ctor, 2, args, &jsTask);
363         if (jsTask == nullptr || status != napi_ok) {
364             REQUEST_HILOGE("Get task failed");
365             return false;
366         }
367         napi_unwrap(context->env_, jsTask, reinterpret_cast<void **>(&context->task));
368         napi_create_reference(context->env_, jsTask, 1, &(context->taskRef));
369         JsTask::AddTaskMap(tid, context->task);
370         JsTask::AddTaskContextMap(tid, context);
371     }
372     return true;
373 }
374 
ParseGetTask(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextInfo> context)375 bool JsTask::ParseGetTask(napi_env env, size_t argc, napi_value *argv, std::shared_ptr<ContextInfo> context)
376 {
377     // need at least 2 params.
378     if (argc < 2) {
379         REQUEST_HILOGE("Wrong number of arguments");
380         return false;
381     }
382     if (NapiUtils::GetValueType(env, argv[1]) != napi_string) {
383         REQUEST_HILOGE("The parameter is not of string type");
384         return false;
385     }
386     std::string tid = NapiUtils::Convert2String(env, argv[1]);
387     if (tid.empty()) {
388         REQUEST_HILOGE("tid is empty");
389         return false;
390     }
391     context->tid = std::stoi(tid);
392     // handle 3rd param TOKEN
393     if (argc == 3) {
394         if (NapiUtils::GetValueType(env, argv[2]) != napi_string) { // argv[2] is the 3rd param
395             REQUEST_HILOGE("The parameter is not of string type");
396             return false;
397         }
398         uint32_t bufferLen = TOKEN_MAX_BYTES + 2;
399         std::unique_ptr<char[]> token = std::make_unique<char[]>(bufferLen);
400         size_t len = 0;
401         napi_status status = napi_get_value_string_utf8(env, argv[2], token.get(), bufferLen, &len);
402         if (status != napi_ok) {
403             REQUEST_HILOGE("napi get value string utf8 failed");
404             memset_s(token.get(), bufferLen, 0, bufferLen);
405             return false;
406         }
407         if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
408             memset_s(token.get(), bufferLen, 0, bufferLen);
409             return false;
410         }
411         context->token = NapiUtils::SHA256(token.get(), len);
412         memset_s(token.get(), bufferLen, 0, bufferLen);
413     }
414     return true;
415 }
416 
Remove(napi_env env,napi_callback_info info)417 napi_value JsTask::Remove(napi_env env, napi_callback_info info)
418 {
419     struct RemoveContext : public AsyncCall::Context {
420         std::string tid;
421         bool res = false;
422     };
423 
424     auto context = std::make_shared<RemoveContext>();
425     context->withErrCode_ = true;
426     context->version_ = Version::API10;
427     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
428         context->tid = ParseTid(context->env_, argc, argv);
429         if (context->tid.empty()) {
430             NapiUtils::ThrowError(context->env_, E_PARAMETER_CHECK, "Parse tid fail!", true);
431             return napi_invalid_arg;
432         }
433         return napi_ok;
434     };
435     auto output = [context](napi_value *result) -> napi_status {
436         if (context->innerCode_ != E_OK) {
437             context->res = false;
438             return napi_generic_failure;
439         }
440         return NapiUtils::Convert2JSValue(context->env_, context->res, *result);
441     };
442     auto exec = [context]() {
443         context->innerCode_ = RequestManager::GetInstance()->Remove(context->tid, Version::API10);
444         // Removed Task can not return notify, so unref in this.
445         JsTask::ClearTaskContext(context->tid);
446     };
447     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
448     AsyncCall asyncCall(env, info, context);
449     return asyncCall.Call(context, "remove");
450 }
451 
ParseTid(napi_env env,size_t argc,napi_value * argv)452 std::string JsTask::ParseTid(napi_env env, size_t argc, napi_value *argv)
453 {
454     if (argc < 1) {
455         REQUEST_HILOGE("Wrong number of arguments");
456         return "";
457     }
458     if (NapiUtils::GetValueType(env, argv[0]) != napi_string) {
459         REQUEST_HILOGE("The first parameter is not of string type");
460         return "";
461     }
462     return NapiUtils::Convert2String(env, argv[0]);
463 }
464 
Show(napi_env env,napi_callback_info info)465 napi_value JsTask::Show(napi_env env, napi_callback_info info)
466 {
467     auto context = std::make_shared<TouchContext>();
468     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
469         context->tid = ParseTid(context->env_, argc, argv);
470         if (context->tid.empty()) {
471             NapiUtils::ThrowError(context->env_, E_PARAMETER_CHECK, "Parse tid fail!", true);
472             return napi_invalid_arg;
473         }
474         return napi_ok;
475     };
476     return TouchInner(env, info, std::move(input), std::move(context));
477 }
478 
Touch(napi_env env,napi_callback_info info)479 napi_value JsTask::Touch(napi_env env, napi_callback_info info)
480 {
481     auto context = std::make_shared<TouchContext>();
482     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
483         bool ret = ParseTouch(context->env_, argc, argv, context);
484         if (!ret) {
485             NapiUtils::ThrowError(context->env_, E_PARAMETER_CHECK, "Parse tid or token fail!", true);
486             return napi_invalid_arg;
487         }
488         return napi_ok;
489     };
490     return TouchInner(env, info, std::move(input), std::move(context));
491 }
492 
TouchInner(napi_env env,napi_callback_info info,AsyncCall::Context::InputAction input,std::shared_ptr<TouchContext> context)493 napi_value JsTask::TouchInner(napi_env env, napi_callback_info info, AsyncCall::Context::InputAction input,
494     std::shared_ptr<TouchContext> context)
495 {
496     context->withErrCode_ = true;
497     context->version_ = Version::API10;
498     auto output = [context](napi_value *result) -> napi_status {
499         if (context->innerCode_ != E_OK) {
500             return napi_generic_failure;
501         }
502         *result = NapiUtils::Convert2JSValue(context->env_, context->taskInfo);
503         return napi_ok;
504     };
505     auto exec = [context]() {
506         if (!RequestManager::GetInstance()->LoadRequestServer()) {
507             context->innerCode_ = E_SERVICE_ERROR;
508             return;
509         }
510         context->innerCode_ = RequestManager::GetInstance()->Touch(context->tid, context->token, context->taskInfo);
511     };
512     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
513     AsyncCall asyncCall(env, info, context);
514     return asyncCall.Call(context, "touch");
515 }
516 
ParseTouch(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<TouchContext> context)517 bool JsTask::ParseTouch(napi_env env, size_t argc, napi_value *argv, std::shared_ptr<TouchContext> context)
518 {
519     // 2 means least param num.
520     if (argc < 2) {
521         REQUEST_HILOGE("Wrong number of arguments");
522         return false;
523     }
524     if (NapiUtils::GetValueType(env, argv[0]) != napi_string || NapiUtils::GetValueType(env, argv[1]) != napi_string) {
525         REQUEST_HILOGE("The parameter is not of string type");
526         return false;
527     }
528     context->tid = NapiUtils::Convert2String(env, argv[0]);
529     if (context->tid.empty()) {
530         REQUEST_HILOGE("tid is empty");
531         return false;
532     }
533     uint32_t bufferLen = TOKEN_MAX_BYTES + 2;
534     char *token = new char[bufferLen];
535     size_t len = 0;
536     napi_status status = napi_get_value_string_utf8(env, argv[1], token, bufferLen, &len);
537     if (status != napi_ok) {
538         REQUEST_HILOGE("napi get value string utf8 failed");
539         memset_s(token, bufferLen, 0, bufferLen);
540         delete[] token;
541         return false;
542     }
543     if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
544         memset_s(token, bufferLen, 0, bufferLen);
545         delete[] token;
546         return false;
547     }
548     context->token = NapiUtils::SHA256(token, len);
549     memset_s(token, bufferLen, 0, bufferLen);
550     delete[] token;
551     return true;
552 }
553 
ParseSearch(napi_env env,size_t argc,napi_value * argv,Filter & filter)554 bool JsTask::ParseSearch(napi_env env, size_t argc, napi_value *argv, Filter &filter)
555 {
556     using namespace std::chrono;
557     filter.bundle = "*";
558     filter.before = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
559     filter.after = filter.before - MILLISECONDS_IN_ONE_DAY;
560     if (argc < 1) {
561         return true;
562     }
563     napi_valuetype valueType = NapiUtils::GetValueType(env, argv[0]);
564     if (valueType == napi_null || valueType == napi_undefined) {
565         return true;
566     }
567     if (valueType != napi_object) {
568         REQUEST_HILOGE("The parameter is not of object type");
569         return false;
570     }
571     filter.bundle = ParseBundle(env, argv[0]);
572     filter.before = ParseBefore(env, argv[0]);
573     filter.after = ParseAfter(env, argv[0], filter.before);
574     if (filter.before < filter.after) {
575         REQUEST_HILOGE("before is small than after");
576         return false;
577     }
578     filter.state = ParseState(env, argv[0]);
579     filter.action = ParseAction(env, argv[0]);
580     filter.mode = ParseMode(env, argv[0]);
581     return true;
582 }
583 
ParseBundle(napi_env env,napi_value value)584 std::string JsTask::ParseBundle(napi_env env, napi_value value)
585 {
586     if (!NapiUtils::HasNamedProperty(env, value, "bundle")) {
587         return "*";
588     }
589     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "bundle");
590     if (NapiUtils::GetValueType(env, value1) != napi_string) {
591         return "*";
592     }
593     return NapiUtils::Convert2String(env, value1);
594 }
595 
ParseState(napi_env env,napi_value value)596 State JsTask::ParseState(napi_env env, napi_value value)
597 {
598     if (!NapiUtils::HasNamedProperty(env, value, "state")) {
599         return State::ANY;
600     }
601     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "state");
602     if (NapiUtils::GetValueType(env, value1) != napi_number) {
603         return State::ANY;
604     }
605     return static_cast<State>(NapiUtils::Convert2Uint32(env, value1));
606 }
607 
ParseAction(napi_env env,napi_value value)608 Action JsTask::ParseAction(napi_env env, napi_value value)
609 {
610     if (!NapiUtils::HasNamedProperty(env, value, "action")) {
611         return Action::ANY;
612     }
613     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "action");
614     if (NapiUtils::GetValueType(env, value1) != napi_number) {
615         return Action::ANY;
616     }
617     return static_cast<Action>(NapiUtils::Convert2Uint32(env, value1));
618 }
619 
ParseMode(napi_env env,napi_value value)620 Mode JsTask::ParseMode(napi_env env, napi_value value)
621 {
622     if (!NapiUtils::HasNamedProperty(env, value, "mode")) {
623         return Mode::ANY;
624     }
625     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "mode");
626     if (NapiUtils::GetValueType(env, value1) != napi_number) {
627         return Mode::ANY;
628     }
629     return static_cast<Mode>(NapiUtils::Convert2Uint32(env, value1));
630 }
631 
ParseBefore(napi_env env,napi_value value)632 int64_t JsTask::ParseBefore(napi_env env, napi_value value)
633 {
634     using namespace std::chrono;
635     int64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
636     if (!NapiUtils::HasNamedProperty(env, value, "before")) {
637         return now;
638     }
639     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "before");
640     if (NapiUtils::GetValueType(env, value1) != napi_number) {
641         return now;
642     }
643     int64_t ret = 0;
644     NAPI_CALL_BASE(env, napi_get_value_int64(env, value1, &ret), now);
645     return ret;
646 }
647 
ParseAfter(napi_env env,napi_value value,int64_t before)648 int64_t JsTask::ParseAfter(napi_env env, napi_value value, int64_t before)
649 {
650     int64_t defaultValue = before - MILLISECONDS_IN_ONE_DAY;
651     if (!NapiUtils::HasNamedProperty(env, value, "after")) {
652         return defaultValue;
653     }
654     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "after");
655     if (NapiUtils::GetValueType(env, value1) != napi_number) {
656         return defaultValue;
657     }
658     int64_t ret = 0;
659     NAPI_CALL_BASE(env, napi_get_value_int64(env, value1, &ret), defaultValue);
660     return ret;
661 }
662 
Search(napi_env env,napi_callback_info info)663 napi_value JsTask::Search(napi_env env, napi_callback_info info)
664 {
665     struct SearchContext : public AsyncCall::Context {
666         Filter filter;
667         std::vector<std::string> tids;
668     };
669 
670     auto context = std::make_shared<SearchContext>();
671     context->withErrCode_ = true;
672     context->version_ = Version::API10;
673     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
674         bool ret = ParseSearch(context->env_, argc, argv, context->filter);
675         if (!ret) {
676             NapiUtils::ThrowError(context->env_, E_PARAMETER_CHECK, "Parse filter fail!", true);
677             return napi_invalid_arg;
678         }
679         return napi_ok;
680     };
681     auto output = [context](napi_value *result) -> napi_status {
682         if (context->innerCode_ != E_OK) {
683             return napi_generic_failure;
684         }
685         *result = NapiUtils::Convert2JSValue(context->env_, context->tids);
686         return napi_ok;
687     };
688     auto exec = [context]() {
689         if (!RequestManager::GetInstance()->LoadRequestServer()) {
690             context->innerCode_ = E_SERVICE_ERROR;
691             return;
692         }
693         context->innerCode_ = RequestManager::GetInstance()->Search(context->filter, context->tids);
694     };
695     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
696     AsyncCall asyncCall(env, info, context);
697     return asyncCall.Call(context, "search");
698 }
699 
Query(napi_env env,napi_callback_info info)700 napi_value JsTask::Query(napi_env env, napi_callback_info info)
701 {
702     struct QueryContext : public AsyncCall::Context {
703         std::string tid;
704         TaskInfo taskInfo;
705     };
706 
707     auto context = std::make_shared<QueryContext>();
708     context->withErrCode_ = true;
709     context->version_ = Version::API10;
710     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
711         context->tid = ParseTid(context->env_, argc, argv);
712         if (context->tid.empty()) {
713             NapiUtils::ThrowError(context->env_, E_PARAMETER_CHECK, "Parse tid fail!", true);
714             return napi_invalid_arg;
715         }
716         return napi_ok;
717     };
718     auto output = [context](napi_value *result) -> napi_status {
719         if (context->innerCode_ != E_OK) {
720             return napi_generic_failure;
721         }
722         context->taskInfo.withSystem = true;
723         *result = NapiUtils::Convert2JSValue(context->env_, context->taskInfo);
724         return napi_ok;
725     };
726     auto exec = [context]() {
727         if (!RequestManager::GetInstance()->LoadRequestServer()) {
728             context->innerCode_ = E_SERVICE_ERROR;
729             return;
730         }
731         context->innerCode_ = RequestManager::GetInstance()->Query(context->tid, context->taskInfo);
732     };
733     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
734     AsyncCall asyncCall(env, info, context);
735     return asyncCall.Call(context, "query");
736 }
737 
GetTid()738 std::string JsTask::GetTid()
739 {
740     return tid_;
741 }
742 
SetTid(int32_t tid)743 void JsTask::SetTid(int32_t tid)
744 {
745     tid_ = std::to_string(tid);
746 }
747 
GetListenerSize(const std::string & key)748 size_t JsTask::GetListenerSize(const std::string &key)
749 {
750     std::lock_guard<std::mutex> autoLock(listenerMutex_);
751     auto it = listenerMap_.find(key);
752     if (it == listenerMap_.end()) {
753         return 0;
754     }
755     REQUEST_HILOGD("listenerMap_ size %{public}zu", it->second.size());
756     return it->second.size();
757 }
758 
AddTaskMap(const std::string & key,JsTask * task)759 void JsTask::AddTaskMap(const std::string &key, JsTask *task)
760 {
761     std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
762     JsTask::taskMap_[key] = task;
763 }
764 
AddTaskContextMap(const std::string & key,std::shared_ptr<ContextInfo> context)765 void JsTask::AddTaskContextMap(const std::string &key, std::shared_ptr<ContextInfo> context)
766 {
767     std::lock_guard<std::mutex> lockGuard(JsTask::taskContextMutex_);
768     JsTask::taskContextMap_[key] = context;
769 }
770 
AddListener(const std::string & key,const sptr<RequestNotify> & listener)771 void JsTask::AddListener(const std::string &key, const sptr<RequestNotify> &listener)
772 {
773     REQUEST_HILOGD("AddListener key %{public}s", key.c_str());
774     std::lock_guard<std::mutex> autoLock(listenerMutex_);
775     listenerMap_[key].push_back(listener);
776 }
777 
RemoveListener(const std::string & type,const std::string & tid,napi_value callback,Version version)778 void JsTask::RemoveListener(const std::string &type, const std::string &tid, napi_value callback, Version version)
779 {
780     std::string key = type + tid;
781     std::lock_guard<std::mutex> autoLock(listenerMutex_);
782     auto it = listenerMap_.find(key);
783     if (it == listenerMap_.end()) {
784         return;
785     }
786     for (auto item = it->second.begin(); item != it->second.end(); item++) {
787         if (Equals((*item)->env_, callback, (*item)->ref_)) {
788             listenerMap_[key].erase(item);
789             break;
790         }
791     }
792     if (listenerMap_[key].empty()) {
793         RequestManager::GetInstance()->Off(type, tid, version);
794         listenerMap_.erase(key);
795     }
796 }
797 
RemoveListener(const std::string & type,const std::string & tid,Version version)798 void JsTask::RemoveListener(const std::string &type, const std::string &tid, Version version)
799 {
800     {
801         std::lock_guard<std::mutex> autoLock(listenerMutex_);
802         auto it = listenerMap_.find(type + tid);
803         if (it == listenerMap_.end()) {
804             return;
805         }
806     }
807     int32_t ret = RequestManager::GetInstance()->Off(type, tid, version);
808     {
809         std::lock_guard<std::mutex> autoLock(listenerMutex_);
810         auto it = listenerMap_.find(type + tid);
811         if (it == listenerMap_.end()) {
812             return;
813         }
814         if (ret == E_OK) {
815             listenerMap_.erase(it);
816         }
817     }
818 }
819 
ClearListener()820 void JsTask::ClearListener()
821 {
822     std::lock_guard<std::mutex> autoLock(listenerMutex_);
823     for (const auto &listener : listenerMap_) {
824         for (const auto &iter : listener.second) {
825             if (iter != nullptr) {
826                 iter->DeleteCallbackRef();
827             }
828         }
829     }
830     listenerMap_.clear();
831 }
832 
ReloadListener()833 void JsTask::ReloadListener()
834 {
835     REQUEST_HILOGD("ReloadListener in");
836     std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
837     for (const auto &it : taskMap_) {
838         std::string tid = it.first;
839         for (auto itListener : it.second->listenerMap_) {
840             std::string key = itListener.first;
841             if (key.find(tid) == std::string::npos) {
842                 continue;
843             }
844             std::string type = key.substr(0, key.find(tid));
845             for (const auto &listener : itListener.second) {
846                 RequestManager::GetInstance()->On(type, tid, listener, it.second->config_.version);
847             }
848         }
849     }
850 }
851 
ClearTaskMap(const std::string & key)852 void JsTask::ClearTaskMap(const std::string &key)
853 {
854     std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
855     auto it = taskMap_.find(key);
856     if (it == taskMap_.end()) {
857         return;
858     }
859     taskMap_.erase(it);
860 }
861 
SetDirsPermission(std::vector<std::string> & dirs)862 bool JsTask::SetDirsPermission(std::vector<std::string> &dirs)
863 {
864     if (dirs.empty()) {
865         return true;
866     }
867     std::string newPath = "/data/storage/el2/base/.ohos/.request/.certs";
868     std::vector<std::string> dirElems;
869     JsInitialize::StringSplit(newPath, '/', dirElems);
870     if (!JsInitialize::CreateDirs(dirElems)) {
871         REQUEST_HILOGE("CreateDirs Err: %{public}s", newPath.c_str());
872         return false;
873     }
874 
875     for (const auto &folderPath : dirs) {
876         fs::path folder = folderPath;
877         if (!(fs::exists(folder) && fs::is_directory(folder))) {
878             return false;
879         }
880         for (const auto &entry : fs::directory_iterator(folder)) {
881             fs::path path = entry.path();
882             std::string existfilePath = folder.string() + "/" + path.filename().string();
883             std::string newfilePath = newPath + "/" + path.filename().string();
884             if (!fs::exists(newfilePath)) {
885                 fs::copy(existfilePath, newfilePath);
886             }
887             if (chmod(newfilePath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
888                 REQUEST_HILOGD("File add OTH access Failed.");
889             }
890             REQUEST_HILOGD("current filePath is %{public}s", newfilePath.c_str());
891             if (!JsTask::SetPathPermission(newfilePath)) {
892                 REQUEST_HILOGE("Set path permission fail.");
893                 return false;
894             }
895         }
896     }
897     if (!dirs.empty()) {
898         dirs.clear();
899         dirs.push_back(newPath);
900     }
901     return true;
902 }
903 
SetPathPermission(const std::string & filepath)904 bool JsTask::SetPathPermission(const std::string &filepath)
905 {
906     std::string baseDir;
907     if (!CheckPathBaseDir(filepath, baseDir)) {
908         return false;
909     }
910 
911     AddPathMap(filepath, baseDir);
912     for (auto it : pathMap_) {
913         if (it.second <= 0) {
914             continue;
915         }
916         if (AclSetAccess(it.first, SA_PERMISSION_X) != ACL_SUCC) {
917             REQUEST_HILOGD("AclSetAccess Parent Dir Failed: %{public}s", it.first.c_str());
918         }
919     }
920 
921     std::string childDir = filepath.substr(0, filepath.rfind("/"));
922     if (AclSetAccess(childDir, SA_PERMISSION_RWX) != ACL_SUCC) {
923         REQUEST_HILOGE("AclSetAccess Child Dir Failed: %{public}s", childDir.c_str());
924         return false;
925     }
926     return true;
927 }
928 
CheckPathBaseDir(const std::string & filepath,std::string & baseDir)929 bool JsTask::CheckPathBaseDir(const std::string &filepath, std::string &baseDir)
930 {
931     if (!JsInitialize::GetBaseDir(baseDir)) {
932         return false;
933     }
934 
935     if (filepath.find(baseDir) != std::string::npos) {
936         return true;
937     }
938     // check baseDir replaced with el2
939     if (baseDir.find(AREA1) != std::string::npos) {
940         baseDir = baseDir.replace(baseDir.find(AREA1), AREA1.length(), AREA2);
941         if (filepath.find(baseDir) == std::string::npos) {
942             REQUEST_HILOGE("File dir not include base dir: %{public}s", baseDir.c_str());
943             return false;
944         }
945         return true;
946     }
947     // check baseDir replaced with el1
948     if (baseDir.find(AREA2) != std::string::npos) {
949         baseDir = baseDir.replace(baseDir.find(AREA2), AREA2.length(), AREA1);
950         if (filepath.find(baseDir) == std::string::npos) {
951             REQUEST_HILOGE("File dir not include base dir: %{public}s", baseDir.c_str());
952             return false;
953         }
954         return true;
955     }
956     return false;
957 }
958 
AddPathMap(const std::string & filepath,const std::string & baseDir)959 void JsTask::AddPathMap(const std::string &filepath, const std::string &baseDir)
960 {
961     std::string childDir(filepath);
962     std::string parentDir;
963     while (childDir.length() > baseDir.length()) {
964         parentDir = childDir.substr(0, childDir.rfind("/"));
965         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
966         auto it = pathMap_.find(parentDir);
967         if (it == pathMap_.end()) {
968             pathMap_[parentDir] = 1;
969         } else {
970             pathMap_[parentDir] += 1;
971         }
972         childDir = parentDir;
973     }
974 }
975 
ResetDirAccess(const std::string & filepath)976 void JsTask::ResetDirAccess(const std::string &filepath)
977 {
978     int ret = AclSetAccess(filepath, SA_PERMISSION_CLEAN);
979     if (ret != ACL_SUCC) {
980         REQUEST_HILOGD("AclSetAccess Reset Dir Failed: %{public}s", filepath.c_str());
981     }
982 }
983 
RemovePathMap(const std::string & filepath)984 void JsTask::RemovePathMap(const std::string &filepath)
985 {
986     std::string baseDir;
987     if (!CheckPathBaseDir(filepath, baseDir)) {
988         return;
989     }
990 
991     if (chmod(filepath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
992         REQUEST_HILOGE("File remove OTH access Failed.");
993     }
994 
995     std::string childDir(filepath);
996     std::string parentDir;
997     while (childDir.length() > baseDir.length()) {
998         parentDir = childDir.substr(0, childDir.rfind("/"));
999         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
1000         auto it = pathMap_.find(parentDir);
1001         if (it != pathMap_.end()) {
1002             if (pathMap_[parentDir] <= 1) {
1003                 pathMap_.erase(parentDir);
1004                 ResetDirAccess(parentDir);
1005             } else {
1006                 pathMap_[parentDir] -= 1;
1007             }
1008         }
1009         childDir = parentDir;
1010     }
1011 }
1012 
RemoveDirsPermission(const std::vector<std::string> & dirs)1013 void JsTask::RemoveDirsPermission(const std::vector<std::string> &dirs)
1014 {
1015     for (const auto &folderPath : dirs) {
1016         fs::path folder = folderPath;
1017         for (const auto &entry : fs::directory_iterator(folder)) {
1018             fs::path path = entry.path();
1019             std::string filePath = folder.string() + "/" + path.filename().string();
1020             RemovePathMap(filePath);
1021         }
1022     }
1023 }
1024 
ClearTaskContext(const std::string & key)1025 void JsTask::ClearTaskContext(const std::string &key)
1026 {
1027     std::lock_guard<std::mutex> lockGuard(JsTask::taskContextMutex_);
1028     auto it = taskContextMap_.find(key);
1029     if (it == taskContextMap_.end()) {
1030         REQUEST_HILOGD("Clear task context, not in ContextMap");
1031         return;
1032     }
1033     auto context = it->second;
1034     auto bodyFileNames = context->task->config_.bodyFileNames;
1035     for (auto &filePath : bodyFileNames) {
1036         NapiUtils::RemoveFile(filePath);
1037     }
1038     // Reset Acl permission
1039     for (auto &file : context->task->config_.files) {
1040         RemovePathMap(file.uri);
1041     }
1042     RemoveDirsPermission(context->task->config_.certsPath);
1043     taskContextMap_.erase(it);
1044     UnrefTaskContextMap(context);
1045 }
1046 
UnrefTaskContextMap(std::shared_ptr<ContextInfo> context)1047 void JsTask::UnrefTaskContextMap(std::shared_ptr<ContextInfo> context)
1048 {
1049     ContextCallbackData *data = new ContextCallbackData();
1050     if (data == nullptr) {
1051         return;
1052     }
1053     data->context = context;
1054     UvQueue::Call(data->context->env_, static_cast<void *>(data), UvUnrefTaskContext);
1055     return;
1056 }
1057 
UvUnrefTaskContext(uv_work_t * work,int status)1058 void JsTask::UvUnrefTaskContext(uv_work_t *work, int status)
1059 {
1060     ContextCallbackData *data = static_cast<ContextCallbackData *>(work->data);
1061     if (data == nullptr) {
1062         // Ensure that the `work` is not nullptr.
1063         delete work;
1064         return;
1065     }
1066     napi_handle_scope scope = nullptr;
1067     napi_open_handle_scope(data->context->env_, &scope);
1068     if (scope == nullptr) {
1069         delete data;
1070         delete work;
1071         return;
1072     }
1073     u_int32_t taskRefCount = 0;
1074     napi_reference_unref(data->context->env_, data->context->taskRef, &taskRefCount);
1075     REQUEST_HILOGD("Unref task ref, count is %{public}d", taskRefCount);
1076     if (taskRefCount == 0) {
1077         napi_delete_reference(data->context->env_, data->context->taskRef);
1078     }
1079     if (data->context->version_ == Version::API10) {
1080         u_int32_t configRefCount = 0;
1081         napi_reference_unref(data->context->env_, data->context->jsConfig, &configRefCount);
1082         REQUEST_HILOGI("Unref task config ref, count is %{public}d", configRefCount);
1083         if (configRefCount == 0) {
1084             napi_delete_reference(data->context->env_, data->context->jsConfig);
1085         }
1086     }
1087     napi_close_handle_scope(data->context->env_, scope);
1088     delete data;
1089     delete work;
1090     return;
1091 }
1092 
Equals(napi_env env,napi_value value,napi_ref copy)1093 bool JsTask::Equals(napi_env env, napi_value value, napi_ref copy)
1094 {
1095     if (copy == nullptr) {
1096         return (value == nullptr);
1097     }
1098 
1099     napi_value copyValue = nullptr;
1100     napi_get_reference_value(env, copy, &copyValue);
1101 
1102     bool isEquals = false;
1103     napi_strict_equals(env, value, copyValue, &isEquals);
1104     return isEquals;
1105 }
1106 
RegisterForegroundResume()1107 void JsTask::RegisterForegroundResume()
1108 {
1109     if (register_) {
1110         return;
1111     }
1112     register_ = true;
1113     auto context = AbilityRuntime::ApplicationContext::GetInstance();
1114     if (context == nullptr) {
1115         REQUEST_HILOGE("Get ApplicationContext failed");
1116         return;
1117     }
1118     context->RegisterAbilityLifecycleCallback(std::make_shared<AppStateCallback>());
1119     REQUEST_HILOGD("Register foreground resume callback success");
1120 }
1121 } // namespace OHOS::Request