• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "cj_request_impl.h"
17 
18 #include <cstdint>
19 #include <string>
20 #include "cj_initialize.h"
21 #include "cj_request_common.h"
22 #include "cj_request_event.h"
23 #include "cj_request_ffi.h"
24 #include "cj_request_task.h"
25 #include "constant.h"
26 #include "log.h"
27 
28 namespace OHOS::CJSystemapi::Request {
29 using OHOS::Request::E_FILE_IO_INFO;
30 using OHOS::Request::E_FILE_PATH_INFO;
31 using OHOS::Request::E_OK_INFO;
32 using OHOS::Request::E_OTHER_INFO;
33 using OHOS::Request::E_PARAMETER_CHECK_INFO;
34 using OHOS::Request::E_PERMISSION_INFO;
35 using OHOS::Request::E_SERVICE_ERROR_INFO;
36 using OHOS::Request::E_TASK_MODE_INFO;
37 using OHOS::Request::E_TASK_NOT_FOUND_INFO;
38 using OHOS::Request::E_TASK_QUEUE_INFO;
39 using OHOS::Request::E_TASK_STATE_INFO;
40 using OHOS::Request::E_UNSUPPORTED_INFO;
41 using OHOS::Request::ExceptionErrorCode;
42 using OHOS::Request::Filter;
43 using OHOS::Request::FUNCTION_PAUSE;
44 using OHOS::Request::FUNCTION_RESUME;
45 using OHOS::Request::FUNCTION_START;
46 using OHOS::Request::FUNCTION_STOP;
47 using OHOS::Request::Reason;
48 using OHOS::Request::TaskInfo;
49 using OHOS::Request::Version;
50 
51 static constexpr const char *NOT_SYSTEM_APP = "permission verification failed, application which is not a system "
52                                               "application uses system API";
53 static const std::map<ExceptionErrorCode, std::string> ErrorCodeToMsg{
54     {ExceptionErrorCode::E_OK, E_OK_INFO},
55     {ExceptionErrorCode::E_PERMISSION, E_PERMISSION_INFO},
56     {ExceptionErrorCode::E_PARAMETER_CHECK, E_PARAMETER_CHECK_INFO},
57     {ExceptionErrorCode::E_UNSUPPORTED, E_UNSUPPORTED_INFO},
58     {ExceptionErrorCode::E_FILE_IO, E_FILE_IO_INFO},
59     {ExceptionErrorCode::E_FILE_PATH, E_FILE_PATH_INFO},
60     {ExceptionErrorCode::E_SERVICE_ERROR, E_SERVICE_ERROR_INFO},
61     {ExceptionErrorCode::E_TASK_QUEUE, E_TASK_QUEUE_INFO},
62     {ExceptionErrorCode::E_TASK_MODE, E_TASK_MODE_INFO},
63     {ExceptionErrorCode::E_TASK_NOT_FOUND, E_TASK_NOT_FOUND_INFO},
64     {ExceptionErrorCode::E_TASK_STATE, E_TASK_STATE_INFO},
65     {ExceptionErrorCode::E_OTHER, E_OTHER_INFO},
66     {ExceptionErrorCode::E_NOT_SYSTEM_APP, NOT_SYSTEM_APP}};
67 
Convert2RetErr(ExceptionErrorCode code)68 RetError CJRequestImpl::Convert2RetErr(ExceptionErrorCode code)
69 {
70     RetError ret = {0};
71     auto iter = ErrorCodeToMsg.find(code);
72     std::string strMsg = (iter != ErrorCodeToMsg.end() ? iter->second : "");
73     ret.errCode = code;
74     ret.errMsg = MallocCString(strMsg);
75     return ret;
76 }
77 
Convert2RetErr(ExceptionError & err)78 RetError CJRequestImpl::Convert2RetErr(ExceptionError &err)
79 {
80     RetError ret = {0};
81     auto iter = ErrorCodeToMsg.find(err.code);
82     std::string strMsg;
83     if (err.errInfo.empty()) {
84         strMsg = (iter != ErrorCodeToMsg.end() ? iter->second : "");
85     } else {
86         strMsg = (iter != ErrorCodeToMsg.end() ? iter->second + "   " : "") + err.errInfo;
87     }
88     ret.errCode = err.code;
89     ret.errMsg = MallocCString(strMsg);
90     return ret;
91 }
92 
ConvertCArr2Map(const CHashStrArr * cheaders)93 std::map<std::string, std::string> CJRequestImpl::ConvertCArr2Map(const CHashStrArr *cheaders)
94 {
95     std::map<std::string, std::string> result;
96     for (int i = 0; i < cheaders->size; ++i) {
97         const CHashStrPair *cheader = &cheaders->headers[i];
98         result[cheader->key] = cheader->value;
99     }
100 
101     return result;
102 }
103 
Convert2Config(CConfig * config,Config & out)104 void CJRequestImpl::Convert2Config(CConfig *config, Config &out)
105 {
106     out.action = static_cast<OHOS::Request::Action>(config->action);
107     out.url = config->url;
108     out.version = Version::API10; // CJ only support API10
109     out.mode = static_cast<OHOS::Request::Mode>(config->mode);
110     out.network = static_cast<OHOS::Request::Network>(config->network);
111     out.index = config->index;
112     out.begins = config->begins;
113     out.ends = config->ends;
114     out.priority = config->priority;
115     out.overwrite = config->overwrite;
116     out.metered = config->metered;
117     out.roaming = config->roaming;
118     out.retry = config->retry;
119     out.redirect = config->redirect;
120     out.gauge = config->gauge;
121     out.precise = config->precise;
122     out.title = config->title;
123     out.saveas = config->saveas;
124     out.method = config->method;
125     out.token = config->token;
126     out.description = config->description;
127     out.headers = ConvertCArr2Map(&config->headers);
128     out.extras = ConvertCArr2Map(&config->extras);
129 }
130 
Convert2RequestData(Action action,std::string & data,const std::vector<FileSpec> & files,const std::vector<FormItem> & forms)131 CConfigDataTypeUion CJRequestImpl::Convert2RequestData(Action action, std::string &data,
132                                                        const std::vector<FileSpec> &files,
133                                                        const std::vector<FormItem> &forms)
134 {
135     CConfigDataTypeUion res{};
136     if (action == Action::DOWNLOAD) {
137         res.str = MallocCString(data);
138     } else {
139         res.formItems = Convert2CFormItemArr(files, forms);
140     }
141     return res;
142 }
143 
Convert2CTaskInfo(TaskInfo & task)144 CTaskInfo CJRequestImpl::Convert2CTaskInfo(TaskInfo &task)
145 {
146     CTaskInfo out = {NULL};
147 
148     if (task.withSystem) {
149         out.uid = MallocCString(task.uid);
150         out.bundle = MallocCString(task.bundle);
151         task.url = "";
152         task.data = "";
153         if (task.action == Action::UPLOAD) {
154             task.files.clear();
155             task.forms.clear();
156         }
157     }
158 
159     out.url = MallocCString(task.url);
160     out.saveas = MallocCString(GetSaveas(task.files, task.action));
161     if (task.action == Action::DOWNLOAD) {
162         out.data.str = MallocCString(task.data);
163     } else {
164         out.data.formItems = Convert2CFormItemArr(task.files, task.forms);
165     }
166     out.data = Convert2RequestData(task.action, task.data, task.files, task.forms);
167 
168     out.tid = MallocCString(task.tid);
169     out.title = MallocCString(task.title);
170     out.description = MallocCString(task.description);
171     out.action = static_cast<uint32_t>(task.action);
172     out.mode = static_cast<uint32_t>(task.mode);
173     out.mimeType = MallocCString(task.mimeType);
174     out.progress = Convert2CProgress(task.progress);
175     out.gauge = task.gauge;
176     out.priority = task.priority;
177     out.ctime = task.ctime;
178     out.mtime = task.mtime;
179     out.retry = task.retry;
180     out.tries = task.tries;
181 
182     if (task.code != Reason::REASON_OK) {
183         out.faults = Convert2Broken(task.code);
184     }
185 
186     out.reason = MallocCString(Convert2ReasonMsg(task.code));
187     out.extras = Convert2CHashStrArr(task.extras);
188 
189     return out;
190 }
191 
CreateTask(OHOS::AbilityRuntime::Context * context,CConfig * ffiConfig)192 RetReqData CJRequestImpl::CreateTask(OHOS::AbilityRuntime::Context *context, CConfig *ffiConfig)
193 {
194     REQUEST_HILOGD("[CJRequestImpl] CreateTask start");
195     Config config{};
196     RetReqData ret{};
197     Convert2Config(ffiConfig, config);
198     ExceptionError result = CJInitialize::ParseConfig(context, ffiConfig, config);
199     if (result.code != 0) {
200         ret.err = Convert2RetErr(result);
201         return ret;
202     }
203 
204     CJRequestTask *task = new (std::nothrow) CJRequestTask();
205     if (task == nullptr) {
206         REQUEST_HILOGE("[CJRequestImpl] Fail to create task.");
207         ret.err.errCode = ExceptionErrorCode::E_OTHER;
208         return ret;
209     }
210     result = task->Create(context, config);
211     if (result.code != 0) {
212         REQUEST_HILOGE("[CJRequestImpl] task create failed, ret:%{public}d.", result.code);
213         delete task;
214         ret.err = Convert2RetErr(result);
215         return ret;
216     }
217 
218     ret.taskId = MallocCString(task->taskId_);
219 
220     REQUEST_HILOGD("[CJRequestImpl] CreateTask end");
221     return ret;
222 }
223 
ParseToken(RequestNativeOptionCString & cToken,std::string & out)224 ExceptionError CJRequestImpl::ParseToken(RequestNativeOptionCString &cToken, std::string &out)
225 {
226     ExceptionError err = {.code = ExceptionErrorCode::E_OK};
227     if (!cToken.hasValue) {
228         out = "null";
229         return err;
230     }
231 
232     size_t len = strlen(cToken.value);
233     if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
234         err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
235         err.errInfo = "Parameter verification failed, the length of token should between 8 and 2048 bytes";
236         return err;
237     }
238     out = SHA256(cToken.value, len);
239     return err;
240 }
241 
Convert2CConfig(Config & in,CConfig & out)242 void CJRequestImpl::Convert2CConfig(Config &in, CConfig &out)
243 {
244     out.action = static_cast<uint32_t>(in.action);
245     out.url = MallocCString(in.url);
246     out.title = MallocCString(in.title);
247     out.description = MallocCString(in.description);
248     out.mode = static_cast<uint32_t>(in.mode);
249     out.overwrite = in.overwrite;
250     out.method = MallocCString(in.method);
251     out.headers = Convert2CHashStrArr(in.headers);
252     out.data = Convert2RequestData(in.action, in.data, in.files, in.forms);
253     out.saveas = MallocCString(in.saveas);
254     out.network = static_cast<uint32_t>(in.network);
255     out.metered = in.metered;
256     out.roaming = in.roaming;
257     out.retry = in.retry;
258     out.redirect = in.redirect;
259     out.index = in.index;
260     out.begins = in.begins;
261     out.ends = in.ends;
262     out.gauge = in.gauge;
263     out.precise = in.precise;
264     out.token = MallocCString(in.token);
265     out.priority = in.priority;
266     out.extras = Convert2CHashStrArr(in.extras);
267 }
268 
GetTask(OHOS::AbilityRuntime::Context * context,std::string taskId,RequestNativeOptionCString & cToken)269 RetTask CJRequestImpl::GetTask(OHOS::AbilityRuntime::Context *context, std::string taskId,
270                                RequestNativeOptionCString &cToken)
271 {
272     RetTask ret{};
273     std::string token = "null";
274     ExceptionError err = ParseToken(cToken, token);
275     if (err.code != 0) {
276         ret.err = Convert2RetErr(err);
277         return ret;
278     }
279     Config out{};
280     err = CJRequestTask::GetTask(context, taskId, token, out);
281     if (err.code != 0) {
282         ret.err = Convert2RetErr(err);
283         return ret;
284     }
285 
286     ret.tid.taskId = MallocCString(taskId);
287     Convert2CConfig(out, ret.tid.config);
288     return ret;
289 }
290 
RemoveTask(std::string taskId)291 RetError CJRequestImpl::RemoveTask(std::string taskId)
292 {
293     RetError ret{};
294     ExceptionError result = CJRequestTask::Remove(taskId);
295     if (result.code != ExceptionErrorCode::E_OK) {
296         return Convert2RetErr(result);
297     }
298 
299     return ret;
300 }
301 
ShowTask(std::string taskId)302 RetTaskInfo CJRequestImpl::ShowTask(std::string taskId)
303 {
304     RetTaskInfo ret{};
305     TaskInfo task{};
306     ExceptionError result = CJRequestTask::Touch(taskId, task);
307     if (result.code != ExceptionErrorCode::E_OK) {
308         ret.err = Convert2RetErr(result);
309         return ret;
310     }
311 
312     ret.task = Convert2CTaskInfo(task);
313     return ret;
314 }
315 
TouchTask(std::string taskId,const char * cToken)316 RetTaskInfo CJRequestImpl::TouchTask(std::string taskId, const char *cToken)
317 {
318     RetTaskInfo ret{};
319     TaskInfo task{};
320     std::string token = "null";
321     RequestNativeOptionCString tmp = {.hasValue = (cToken != NULL), .value = cToken};
322     ExceptionError err = ParseToken(tmp, token);
323     if (err.code != 0) {
324         ret.err = Convert2RetErr(err);
325         return ret;
326     }
327 
328     err = CJRequestTask::Touch(taskId, task, token);
329     if (err.code != ExceptionErrorCode::E_OK) {
330         ret.err = Convert2RetErr(err);
331         return ret;
332     }
333 
334     ret.task = Convert2CTaskInfo(task);
335     return ret;
336 }
337 
Convert2CStringArray(std::vector<std::string> & tids)338 RequestCArrString CJRequestImpl::Convert2CStringArray(std::vector<std::string> &tids)
339 {
340     RequestCArrString res{};
341     if (tids.empty()) {
342         return res;
343     }
344 
345     size_t size = tids.size();
346     if (size == 0 || size > std::numeric_limits<size_t>::max() / sizeof(char *)) {
347         return res;
348     }
349     res.head = static_cast<char **>(malloc(sizeof(char *) * size));
350     if (!res.head) {
351         return res;
352     }
353 
354     size_t i = 0;
355     for (; i < size; ++i) {
356         res.head[i] = MallocCString(tids[i]);
357     }
358     res.size = static_cast<int64_t>(i);
359 
360     return res;
361 }
362 
ParseBundle(RequestNativeOptionCString & bundle)363 std::string CJRequestImpl::ParseBundle(RequestNativeOptionCString &bundle)
364 {
365     return bundle.hasValue ? bundle.value : "*";
366 }
367 
ParseBefore(RequestNativeOptionInt64 & before)368 int64_t CJRequestImpl::ParseBefore(RequestNativeOptionInt64 &before)
369 {
370     using namespace std::chrono;
371     int64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
372 
373     return before.hasValue ? before.value : now;
374 }
375 
376 constexpr int64_t MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
ParseAfter(RequestNativeOptionInt64 & after,int64_t before)377 int64_t CJRequestImpl::ParseAfter(RequestNativeOptionInt64 &after, int64_t before)
378 {
379     return after.hasValue ? after.value : (before - MILLISECONDS_IN_ONE_DAY);
380 }
381 
ParseState(RequestNativeOptionUInt32 & state)382 State CJRequestImpl::ParseState(RequestNativeOptionUInt32 &state)
383 {
384     return state.hasValue ? static_cast<State>(state.value) : State::ANY;
385 }
386 
ParseAction(RequestNativeOptionUInt32 & action)387 Action CJRequestImpl::ParseAction(RequestNativeOptionUInt32 &action)
388 {
389     return action.hasValue ? static_cast<Action>(action.value) : Action::ANY;
390 }
391 
ParseMode(RequestNativeOptionUInt32 & mode)392 Mode CJRequestImpl::ParseMode(RequestNativeOptionUInt32 &mode)
393 {
394     return mode.hasValue ? static_cast<Mode>(mode.value) : Mode::ANY;
395 }
396 
Convert2Filter(CFilter & filter,Filter & out)397 ExceptionError CJRequestImpl::Convert2Filter(CFilter &filter, Filter &out)
398 {
399     ExceptionError err = {.code = ExceptionErrorCode::E_OK};
400     out.bundle = ParseBundle(filter.bundle);
401     out.before = ParseBefore(filter.before);
402     out.after = ParseAfter(filter.after, out.before);
403     if (out.before < out.after) {
404         REQUEST_HILOGE("before is small than after");
405         err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
406         err.errInfo = "Parameter verification failed, filter before is small than after";
407         return err;
408     }
409 
410     out.state = ParseState(filter.state);
411     out.action = ParseAction(filter.action);
412     out.mode = ParseMode(filter.mode);
413     return err;
414 }
415 
SearchTask(CFilter & filter)416 RetTaskArr CJRequestImpl::SearchTask(CFilter &filter)
417 {
418     RetTaskArr ret{};
419     Filter para{};
420     ExceptionError result = Convert2Filter(filter, para);
421     if (result.code != ExceptionErrorCode::E_OK) {
422         ret.err = Convert2RetErr(result);
423         return ret;
424     }
425 
426     std::vector<std::string> tids;
427     result = CJRequestTask::Search(para, tids);
428     if (result.code != ExceptionErrorCode::E_OK) {
429         ret.err = Convert2RetErr(result);
430         return ret;
431     }
432 
433     ret.tasks = Convert2CStringArray(tids);
434     return ret;
435 }
436 
FreeTask(std::string taskId)437 void CJRequestImpl::FreeTask(std::string taskId)
438 {
439     REQUEST_HILOGD("[CJRequestImpl] FreeTask start");
440     delete CJRequestTask::ClearTaskMap(taskId);
441 }
442 
ProgressOn(char * event,std::string taskId,void * callback)443 RetError CJRequestImpl::ProgressOn(char *event, std::string taskId, void *callback)
444 {
445     REQUEST_HILOGD("[CJRequestImpl] ProgressOn start");
446     RetError ret{};
447     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
448     if (task == nullptr) {
449         REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}s.", taskId.c_str());
450         return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
451     }
452 
453     ExceptionError result = task->On(event, taskId, callback);
454     if (result.code != 0) {
455         REQUEST_HILOGE("[CJRequestImpl] task on failed, ret:%{public}d.", result.code);
456         return Convert2RetErr(result);
457     }
458 
459     return ret;
460 }
461 
ProgressOff(char * event,std::string taskId,void * callback)462 RetError CJRequestImpl::ProgressOff(char *event, std::string taskId, void *callback)
463 {
464     REQUEST_HILOGD("[CJRequestImpl] ProgressOff start");
465     RetError ret{};
466     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
467     if (task == nullptr) {
468         REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}s.", taskId.c_str());
469         return ret;
470     }
471 
472     ExceptionError result = task->Off(event, callback);
473     if (result.code != 0) {
474         REQUEST_HILOGE("[CJRequestImpl] task off failed, ret:%{public}d.", result.code);
475         return Convert2RetErr(result);
476     }
477 
478     return ret;
479 }
480 
TaskExec(std::string execType,std::string taskId)481 RetError CJRequestImpl::TaskExec(std::string execType, std::string taskId)
482 {
483     REQUEST_HILOGD("[CJRequestImpl] TaskExec start");
484     RetError ret{};
485     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
486     if (task == nullptr) {
487         REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}s.", taskId.c_str());
488         return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
489     }
490 
491     ExceptionErrorCode code = CJRequestEvent::Exec(execType, task);
492     if (code != ExceptionErrorCode::E_OK) {
493         return Convert2RetErr(code);
494     }
495 
496     return ret;
497 }
498 
TaskStart(std::string taskId)499 RetError CJRequestImpl::TaskStart(std::string taskId)
500 {
501     return CJRequestImpl::TaskExec(FUNCTION_START, taskId);
502 }
503 
TaskPause(std::string taskId)504 RetError CJRequestImpl::TaskPause(std::string taskId)
505 {
506     return CJRequestImpl::TaskExec(FUNCTION_PAUSE, taskId);
507 }
508 
TaskResume(std::string taskId)509 RetError CJRequestImpl::TaskResume(std::string taskId)
510 {
511     return CJRequestImpl::TaskExec(FUNCTION_RESUME, taskId);
512 }
513 
TaskStop(std::string taskId)514 RetError CJRequestImpl::TaskStop(std::string taskId)
515 {
516     return CJRequestImpl::TaskExec(FUNCTION_STOP, taskId);
517 }
518 } // namespace OHOS::CJSystemapi::Request
519