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