• 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     REQUEST_HILOGD("[CJRequestImpl] CreateTask end");
220     return ret;
221 }
222 
ParseToken(RequestNativeOptionCString & cToken,std::string & out)223 ExceptionError CJRequestImpl::ParseToken(RequestNativeOptionCString &cToken, std::string &out)
224 {
225     ExceptionError err = {.code = ExceptionErrorCode::E_OK};
226     if (!cToken.hasValue) {
227         out = "null";
228         return err;
229     }
230 
231     size_t len = strlen(cToken.value);
232     if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
233         err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
234         err.errInfo = "Parameter verification failed, the length of token should between 8 and 2048 bytes";
235         return err;
236     }
237     out = SHA256(cToken.value, len);
238     return err;
239 }
240 
Convert2CConfig(Config & in,CConfig & out)241 void CJRequestImpl::Convert2CConfig(Config &in, CConfig &out)
242 {
243     out.action = static_cast<uint32_t>(in.action);
244     out.url = MallocCString(in.url);
245     out.title = MallocCString(in.title);
246     out.description = MallocCString(in.description);
247     out.mode = static_cast<uint32_t>(in.mode);
248     out.overwrite = in.overwrite;
249     out.method = MallocCString(in.method);
250     out.headers = Convert2CHashStrArr(in.headers);
251     out.data = Convert2RequestData(in.action, in.data, in.files, in.forms);
252     out.saveas = MallocCString(in.saveas);
253     out.network = static_cast<uint32_t>(in.network);
254     out.metered = in.metered;
255     out.roaming = in.roaming;
256     out.retry = in.retry;
257     out.redirect = in.redirect;
258     out.index = in.index;
259     out.begins = in.begins;
260     out.ends = in.ends;
261     out.gauge = in.gauge;
262     out.precise = in.precise;
263     out.token = MallocCString(in.token);
264     out.priority = in.priority;
265     out.extras = Convert2CHashStrArr(in.extras);
266 }
267 
GetTask(OHOS::AbilityRuntime::Context * context,std::string taskId,RequestNativeOptionCString & cToken)268 RetTask CJRequestImpl::GetTask(OHOS::AbilityRuntime::Context *context, std::string taskId,
269                                RequestNativeOptionCString &cToken)
270 {
271     RetTask ret{};
272     std::string token = "null";
273     ExceptionError err = ParseToken(cToken, token);
274     if (err.code != 0) {
275         ret.err = Convert2RetErr(err);
276         return ret;
277     }
278     Config out{};
279     err = CJRequestTask::GetTask(context, taskId, token, out);
280     if (err.code != 0) {
281         ret.err = Convert2RetErr(err);
282         return ret;
283     }
284 
285     ret.tid.taskId = MallocCString(taskId);
286     Convert2CConfig(out, ret.tid.config);
287     return ret;
288 }
289 
RemoveTask(std::string taskId)290 RetError CJRequestImpl::RemoveTask(std::string taskId)
291 {
292     RetError ret{};
293     ExceptionError result = CJRequestTask::Remove(taskId);
294     if (result.code != ExceptionErrorCode::E_OK) {
295         return Convert2RetErr(result);
296     }
297 
298     return ret;
299 }
300 
ShowTask(std::string taskId)301 RetTaskInfo CJRequestImpl::ShowTask(std::string taskId)
302 {
303     RetTaskInfo ret{};
304     TaskInfo task{};
305     ExceptionError result = CJRequestTask::Touch(taskId, task);
306     if (result.code != ExceptionErrorCode::E_OK) {
307         ret.err = Convert2RetErr(result);
308         return ret;
309     }
310 
311     ret.task = Convert2CTaskInfo(task);
312     return ret;
313 }
314 
TouchTask(std::string taskId,const char * cToken)315 RetTaskInfo CJRequestImpl::TouchTask(std::string taskId, const char *cToken)
316 {
317     RetTaskInfo ret{};
318     TaskInfo task{};
319     std::string token = "null";
320     RequestNativeOptionCString tmp = {.hasValue = (cToken != NULL), .value = cToken};
321     ExceptionError err = ParseToken(tmp, token);
322     if (err.code != 0) {
323         ret.err = Convert2RetErr(err);
324         return ret;
325     }
326 
327     err = CJRequestTask::Touch(taskId, task, token);
328     if (err.code != ExceptionErrorCode::E_OK) {
329         ret.err = Convert2RetErr(err);
330         return ret;
331     }
332 
333     ret.task = Convert2CTaskInfo(task);
334     return ret;
335 }
336 
Convert2CStringArray(std::vector<std::string> & tids)337 RequestCArrString CJRequestImpl::Convert2CStringArray(std::vector<std::string> &tids)
338 {
339     RequestCArrString res{};
340     if (tids.empty()) {
341         return res;
342     }
343 
344     size_t size = tids.size();
345     if (size == 0 || size > std::numeric_limits<size_t>::max() / sizeof(char *)) {
346         return res;
347     }
348     res.head = static_cast<char **>(malloc(sizeof(char *) * size));
349     if (!res.head) {
350         return res;
351     }
352 
353     size_t i = 0;
354     for (; i < size; ++i) {
355         res.head[i] = MallocCString(tids[i]);
356     }
357     res.size = static_cast<int64_t>(i);
358 
359     return res;
360 }
361 
ParseBundle(RequestNativeOptionCString & bundle)362 std::string CJRequestImpl::ParseBundle(RequestNativeOptionCString &bundle)
363 {
364     return bundle.hasValue ? bundle.value : "*";
365 }
366 
ParseBefore(RequestNativeOptionInt64 & before)367 int64_t CJRequestImpl::ParseBefore(RequestNativeOptionInt64 &before)
368 {
369     using namespace std::chrono;
370     int64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
371 
372     return before.hasValue ? before.value : now;
373 }
374 
375 constexpr int64_t MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
ParseAfter(RequestNativeOptionInt64 & after,int64_t before)376 int64_t CJRequestImpl::ParseAfter(RequestNativeOptionInt64 &after, int64_t before)
377 {
378     return after.hasValue ? after.value : (before - MILLISECONDS_IN_ONE_DAY);
379 }
380 
ParseState(RequestNativeOptionUInt32 & state)381 State CJRequestImpl::ParseState(RequestNativeOptionUInt32 &state)
382 {
383     return state.hasValue ? static_cast<State>(state.value) : State::ANY;
384 }
385 
ParseAction(RequestNativeOptionUInt32 & action)386 Action CJRequestImpl::ParseAction(RequestNativeOptionUInt32 &action)
387 {
388     return action.hasValue ? static_cast<Action>(action.value) : Action::ANY;
389 }
390 
ParseMode(RequestNativeOptionUInt32 & mode)391 Mode CJRequestImpl::ParseMode(RequestNativeOptionUInt32 &mode)
392 {
393     return mode.hasValue ? static_cast<Mode>(mode.value) : Mode::ANY;
394 }
395 
Convert2Filter(CFilter & filter,Filter & out)396 ExceptionError CJRequestImpl::Convert2Filter(CFilter &filter, Filter &out)
397 {
398     ExceptionError err = {.code = ExceptionErrorCode::E_OK};
399     out.bundle = ParseBundle(filter.bundle);
400     out.before = ParseBefore(filter.before);
401     out.after = ParseAfter(filter.after, out.before);
402     if (out.before < out.after) {
403         REQUEST_HILOGE("before is small than after");
404         err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
405         err.errInfo = "Parameter verification failed, filter before is small than after";
406         return err;
407     }
408 
409     out.state = ParseState(filter.state);
410     out.action = ParseAction(filter.action);
411     out.mode = ParseMode(filter.mode);
412     return err;
413 }
414 
SearchTask(CFilter & filter)415 RetTaskArr CJRequestImpl::SearchTask(CFilter &filter)
416 {
417     RetTaskArr ret{};
418     Filter para{};
419     ExceptionError result = Convert2Filter(filter, para);
420     if (result.code != ExceptionErrorCode::E_OK) {
421         ret.err = Convert2RetErr(result);
422         return ret;
423     }
424 
425     std::vector<std::string> tids;
426     result = CJRequestTask::Search(para, tids);
427     if (result.code != ExceptionErrorCode::E_OK) {
428         ret.err = Convert2RetErr(result);
429         return ret;
430     }
431 
432     ret.tasks = Convert2CStringArray(tids);
433     return ret;
434 }
435 
FreeTask(std::string taskId)436 void CJRequestImpl::FreeTask(std::string taskId)
437 {
438     REQUEST_HILOGD("[CJRequestImpl] FreeTask start");
439     delete CJRequestTask::ClearTaskMap(taskId);
440 }
441 
ProgressOn(char * event,std::string taskId,void * callback)442 RetError CJRequestImpl::ProgressOn(char *event, std::string taskId, void *callback)
443 {
444     REQUEST_HILOGD("[CJRequestImpl] ProgressOn start");
445     RetError ret{};
446     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
447     if (task == nullptr) {
448         REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}s.", taskId.c_str());
449         return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
450     }
451 
452     ExceptionError result = task->On(event, taskId, callback);
453     if (result.code != 0) {
454         REQUEST_HILOGE("[CJRequestImpl] task on failed, ret:%{public}d.", result.code);
455         return Convert2RetErr(result);
456     }
457 
458     return ret;
459 }
460 
ProgressOff(char * event,std::string taskId,void * callback)461 RetError CJRequestImpl::ProgressOff(char *event, std::string taskId, void *callback)
462 {
463     REQUEST_HILOGD("[CJRequestImpl] ProgressOff start");
464     RetError ret{};
465     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
466     if (task == nullptr) {
467         REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}s.", taskId.c_str());
468         return ret;
469     }
470 
471     ExceptionError result = task->Off(event, callback);
472     if (result.code != 0) {
473         REQUEST_HILOGE("[CJRequestImpl] task off failed, ret:%{public}d.", result.code);
474         return Convert2RetErr(result);
475     }
476 
477     return ret;
478 }
479 
TaskExec(std::string execType,std::string taskId)480 RetError CJRequestImpl::TaskExec(std::string execType, std::string taskId)
481 {
482     REQUEST_HILOGD("[CJRequestImpl] TaskExec start");
483     RetError ret{};
484     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
485     if (task == nullptr) {
486         REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}s.", taskId.c_str());
487         return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
488     }
489 
490     ExceptionErrorCode code = CJRequestEvent::Exec(execType, task);
491     if (code != ExceptionErrorCode::E_OK) {
492         return Convert2RetErr(code);
493     }
494 
495     return ret;
496 }
497 
TaskStart(std::string taskId)498 RetError CJRequestImpl::TaskStart(std::string taskId)
499 {
500     return CJRequestImpl::TaskExec(FUNCTION_START, taskId);
501 }
502 
TaskPause(std::string taskId)503 RetError CJRequestImpl::TaskPause(std::string taskId)
504 {
505     return CJRequestImpl::TaskExec(FUNCTION_PAUSE, taskId);
506 }
507 
TaskResume(std::string taskId)508 RetError CJRequestImpl::TaskResume(std::string taskId)
509 {
510     return CJRequestImpl::TaskExec(FUNCTION_RESUME, taskId);
511 }
512 
TaskStop(std::string taskId)513 RetError CJRequestImpl::TaskStop(std::string taskId)
514 {
515     return CJRequestImpl::TaskExec(FUNCTION_STOP, taskId);
516 }
517 } // namespace OHOS::CJSystemapi::Request
518