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