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 "request_action.h"
17
18 #include <fcntl.h>
19 #include <securec.h>
20 #include <sys/stat.h>
21
22 #include <filesystem>
23 #include <fstream>
24 #include <memory>
25 #include <string>
26 #include <unordered_map>
27 #include <vector>
28
29 #include "access_token.h"
30 #include "accesstoken_kit.h"
31 #include "application_context.h"
32 #include "constant.h"
33 #include "data_ability_helper.h"
34 #include "ffrt.h"
35 #include "file_uri.h"
36 #include "log.h"
37 #include "path_control.h"
38 #include "request_common.h"
39 #include "request_manager.h"
40 #include "storage_acl.h"
41
42 namespace OHOS::Request {
43 using namespace OHOS::Security::AccessToken;
44 using namespace OHOS::StorageDaemon;
45 namespace fs = std::filesystem;
46
47 static std::mutex taskMutex_;
48 static std::map<std::string, Config> taskMap_;
49
GetInstance()50 const std::unique_ptr<RequestAction> &RequestAction::GetInstance()
51 {
52 static std::unique_ptr<RequestAction> instance = std::make_unique<RequestAction>();
53 return instance;
54 }
55
Start(const std::string & tid)56 int32_t RequestAction::Start(const std::string &tid)
57 {
58 return RequestManager::GetInstance()->Start(tid);
59 }
Stop(const std::string & tid)60 int32_t RequestAction::Stop(const std::string &tid)
61 {
62 return RequestManager::GetInstance()->Stop(tid);
63 }
64
Touch(const std::string & tid,const std::string & token,TaskInfo & info)65 int32_t RequestAction::Touch(const std::string &tid, const std::string &token, TaskInfo &info)
66 {
67 return RequestManager::GetInstance()->Touch(tid, token, info);
68 }
69
Show(const std::string & tid,TaskInfo & info)70 int32_t RequestAction::Show(const std::string &tid, TaskInfo &info)
71 {
72 return RequestManager::GetInstance()->Show(tid, info);
73 }
74
Pause(const std::string & tid)75 int32_t RequestAction::Pause(const std::string &tid)
76 {
77 return RequestManager::GetInstance()->Pause(tid, Version::API10);
78 }
79
Resume(const std::string & tid)80 int32_t RequestAction::Resume(const std::string &tid)
81 {
82 return RequestManager::GetInstance()->Resume(tid);
83 }
84
SetMaxSpeed(const std::string & tid,const int64_t maxSpeed)85 int32_t RequestAction::SetMaxSpeed(const std::string &tid, const int64_t maxSpeed)
86 {
87 return RequestManager::GetInstance()->SetMaxSpeed(tid, maxSpeed);
88 }
89
StartTasks(const std::vector<std::string> & tids,std::unordered_map<std::string,ExceptionErrorCode> & rets)90 ExceptionErrorCode RequestAction::StartTasks(
91 const std::vector<std::string> &tids, std::unordered_map<std::string, ExceptionErrorCode> &rets)
92 {
93 rets.clear();
94 std::vector<ExceptionErrorCode> vec;
95 ExceptionErrorCode code = RequestManager::GetInstance()->StartTasks(tids, vec);
96 if (code != ExceptionErrorCode::E_OK) {
97 return code;
98 }
99 uint32_t len = static_cast<uint32_t>(tids.size());
100 for (uint32_t i = 0; i < len; i++) {
101 rets.insert_or_assign(tids[i], vec[i]);
102 }
103 return ExceptionErrorCode::E_OK;
104 }
105
StopTasks(const std::vector<std::string> & tids,std::unordered_map<std::string,ExceptionErrorCode> & rets)106 ExceptionErrorCode RequestAction::StopTasks(
107 const std::vector<std::string> &tids, std::unordered_map<std::string, ExceptionErrorCode> &rets)
108 {
109 rets.clear();
110 std::vector<ExceptionErrorCode> vec;
111 ExceptionErrorCode code = RequestManager::GetInstance()->StopTasks(tids, vec);
112 if (code != ExceptionErrorCode::E_OK) {
113 return code;
114 }
115 uint32_t len = static_cast<uint32_t>(tids.size());
116 for (uint32_t i = 0; i < len; i++) {
117 rets.insert_or_assign(tids[i], vec[i]);
118 }
119 return ExceptionErrorCode::E_OK;
120 }
121
ResumeTasks(const std::vector<std::string> & tids,std::unordered_map<std::string,ExceptionErrorCode> & rets)122 ExceptionErrorCode RequestAction::ResumeTasks(
123 const std::vector<std::string> &tids, std::unordered_map<std::string, ExceptionErrorCode> &rets)
124 {
125 rets.clear();
126 std::vector<ExceptionErrorCode> vec;
127 ExceptionErrorCode code = RequestManager::GetInstance()->ResumeTasks(tids, vec);
128 if (code != ExceptionErrorCode::E_OK) {
129 return code;
130 }
131 uint32_t len = static_cast<uint32_t>(tids.size());
132 for (uint32_t i = 0; i < len; i++) {
133 rets.insert_or_assign(tids[i], vec[i]);
134 }
135 return ExceptionErrorCode::E_OK;
136 }
137
PauseTasks(const std::vector<std::string> & tids,std::unordered_map<std::string,ExceptionErrorCode> & rets)138 ExceptionErrorCode RequestAction::PauseTasks(
139 const std::vector<std::string> &tids, std::unordered_map<std::string, ExceptionErrorCode> &rets)
140 {
141 rets.clear();
142 std::vector<ExceptionErrorCode> vec;
143 ExceptionErrorCode code = RequestManager::GetInstance()->PauseTasks(tids, Version::API10, vec);
144 if (code != ExceptionErrorCode::E_OK) {
145 return code;
146 }
147 uint32_t len = static_cast<uint32_t>(tids.size());
148 for (uint32_t i = 0; i < len; i++) {
149 rets.insert_or_assign(tids[i], vec[i]);
150 }
151 return ExceptionErrorCode::E_OK;
152 }
153
ShowTasks(const std::vector<std::string> & tids,std::unordered_map<std::string,TaskInfoRet> & rets)154 ExceptionErrorCode RequestAction::ShowTasks(
155 const std::vector<std::string> &tids, std::unordered_map<std::string, TaskInfoRet> &rets)
156 {
157 rets.clear();
158 std::vector<TaskInfoRet> vec;
159 ExceptionErrorCode code = RequestManager::GetInstance()->ShowTasks(tids, vec);
160 if (code != ExceptionErrorCode::E_OK) {
161 return code;
162 }
163 uint32_t len = static_cast<uint32_t>(tids.size());
164 for (uint32_t i = 0; i < len; i++) {
165 rets.insert_or_assign(tids[i], vec[i]);
166 }
167 return ExceptionErrorCode::E_OK;
168 }
169
TouchTasks(const std::vector<TaskIdAndToken> & tidTokens,std::unordered_map<std::string,TaskInfoRet> & rets)170 ExceptionErrorCode RequestAction::TouchTasks(
171 const std::vector<TaskIdAndToken> &tidTokens, std::unordered_map<std::string, TaskInfoRet> &rets)
172 {
173 rets.clear();
174 std::vector<TaskInfoRet> vec;
175 ExceptionErrorCode code = RequestManager::GetInstance()->TouchTasks(tidTokens, vec);
176 if (code != ExceptionErrorCode::E_OK) {
177 return code;
178 }
179 uint32_t len = static_cast<uint32_t>(tidTokens.size());
180 for (uint32_t i = 0; i < len; i++) {
181 rets.insert_or_assign(tidTokens[i].tid, vec[i]);
182 }
183 return ExceptionErrorCode::E_OK;
184 }
185
SetMaxSpeeds(const std::vector<SpeedConfig> & speedConfig,std::unordered_map<std::string,ExceptionErrorCode> & rets)186 ExceptionErrorCode RequestAction::SetMaxSpeeds(
187 const std::vector<SpeedConfig> &speedConfig, std::unordered_map<std::string, ExceptionErrorCode> &rets)
188 {
189 rets.clear();
190 std::vector<ExceptionErrorCode> vec;
191 ExceptionErrorCode code = RequestManager::GetInstance()->SetMaxSpeeds(speedConfig, vec);
192 if (code != ExceptionErrorCode::E_OK) {
193 return code;
194 }
195 uint32_t len = static_cast<uint32_t>(speedConfig.size());
196 for (uint32_t i = 0; i < len; i++) {
197 rets.insert_or_assign(speedConfig[i].tid, vec[i]);
198 }
199 return ExceptionErrorCode::E_OK;
200 }
201
SetMode(std::string & tid,Mode mode)202 ExceptionErrorCode RequestAction::SetMode(std::string &tid, Mode mode)
203 {
204 return RequestManager::GetInstance()->SetMode(tid, mode);
205 }
206
DisableTaskNotification(const std::vector<std::string> & tids,std::unordered_map<std::string,ExceptionErrorCode> & rets)207 ExceptionErrorCode RequestAction::DisableTaskNotification(
208 const std::vector<std::string> &tids, std::unordered_map<std::string, ExceptionErrorCode> &rets)
209 {
210 rets.clear();
211 std::vector<ExceptionErrorCode> vec;
212 ExceptionErrorCode code = RequestManager::GetInstance()->DisableTaskNotification(tids, vec);
213 for (size_t i = 0; i < tids.size() && i < vec.size(); i++) {
214 rets.insert_or_assign(tids[i], vec[i]);
215 }
216 return code;
217 }
218
CreateDirs(const std::vector<std::string> & pathDirs)219 bool RequestAction::CreateDirs(const std::vector<std::string> &pathDirs)
220 {
221 std::string path;
222 std::error_code err;
223 for (auto elem : pathDirs) {
224 path += "/" + elem;
225 if (std::filesystem::exists(path, err)) {
226 continue;
227 }
228 err.clear();
229 // create_directory noexcept.
230 if (!std::filesystem::create_directory(path, err)) {
231 REQUEST_HILOGE("Create Dir Err: %{public}d, %{public}s", err.value(), err.message().c_str());
232 return false;
233 }
234 }
235 return true;
236 }
237
FileToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,const Config & config,std::string & path)238 bool RequestAction::FileToWhole(
239 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config, std::string &path)
240 {
241 std::string bundleName = path.substr(0, path.find("/"));
242 if (bundleName != config.bundleName) {
243 REQUEST_HILOGE("path bundleName error.");
244 return false;
245 }
246 path.erase(0, bundleName.size());
247 return true;
248 }
249
BaseToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,std::string & path)250 bool RequestAction::BaseToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, std::string &path)
251 {
252 std::string base = context->GetBaseDir();
253 if (base.empty()) {
254 REQUEST_HILOGE("GetBaseDir error.");
255 return false;
256 }
257 path = base + "/" + path;
258 return true;
259 }
260
CacheToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,std::string & path)261 bool RequestAction::CacheToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, std::string &path)
262 {
263 std::string cache = context->GetCacheDir();
264 if (cache.empty()) {
265 REQUEST_HILOGE("GetCacheDir error.");
266 return false;
267 }
268 path = cache + "/" + path;
269 return true;
270 }
271
StandardizePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,const Config & config,std::string & path)272 bool RequestAction::StandardizePath(
273 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config, std::string &path)
274 {
275 std::string wholePrefix = "/";
276 std::string filePrefix = "file://";
277 std::string internalPrefix = "internal://";
278 std::string currentPrefix = "./";
279
280 if (path.find(wholePrefix) == 0) {
281 return true;
282 }
283 if (path.find(filePrefix) == 0) {
284 path.erase(0, filePrefix.size());
285 return FileToWhole(context, config, path);
286 }
287 if (path.find(internalPrefix) == 0) {
288 path.erase(0, internalPrefix.size());
289 return BaseToWhole(context, path);
290 }
291 if (path.find(currentPrefix) == 0) {
292 path.erase(0, currentPrefix.size());
293 return CacheToWhole(context, path);
294 }
295 return CacheToWhole(context, path);
296 }
297
StringSplit(const std::string & str,const char delim,std::vector<std::string> & elems)298 void RequestAction::StringSplit(const std::string &str, const char delim, std::vector<std::string> &elems)
299 {
300 std::stringstream stream(str);
301 std::string item;
302 while (std::getline(stream, item, delim)) {
303 if (!item.empty()) {
304 elems.push_back(item);
305 }
306 }
307 return;
308 }
309
PathVecToNormal(const std::vector<std::string> & in,std::vector<std::string> & out)310 bool RequestAction::PathVecToNormal(const std::vector<std::string> &in, std::vector<std::string> &out)
311 {
312 for (auto elem : in) {
313 if (elem == "..") {
314 if (out.size() > 0) {
315 out.pop_back();
316 } else {
317 return false;
318 }
319 } else {
320 out.push_back(elem);
321 }
322 }
323 return true;
324 }
325
WholeToNormal(std::string & path,std::vector<std::string> & out)326 bool RequestAction::WholeToNormal(std::string &path, std::vector<std::string> &out)
327 {
328 std::string normalPath;
329 std::vector<std::string> elems;
330 StringSplit(path, '/', elems);
331 if (!PathVecToNormal(elems, out)) {
332 return false;
333 }
334 for (auto elem : out) {
335 normalPath += "/" + elem;
336 }
337 path = normalPath;
338 return true;
339 }
340
GetAppBaseDir(std::string & baseDir)341 bool RequestAction::GetAppBaseDir(std::string &baseDir)
342 {
343 auto context = AbilityRuntime::Context::GetApplicationContext();
344 if (context == nullptr) {
345 REQUEST_HILOGE("AppContext is null.");
346 return false;
347 }
348 baseDir = context->GetBaseDir();
349 if (baseDir.empty()) {
350 REQUEST_HILOGE("Base dir not found.");
351 return false;
352 }
353 return true;
354 }
355
CheckBelongAppBaseDir(const std::string & filepath,std::string & baseDir)356 bool RequestAction::CheckBelongAppBaseDir(const std::string &filepath, std::string &baseDir)
357 {
358 if (!GetAppBaseDir(baseDir)) {
359 return false;
360 }
361 return FindAreaPath(filepath);
362 }
363
FindAreaPath(const std::string & filepath)364 bool RequestAction::FindAreaPath(const std::string &filepath)
365 {
366 if (PathControl::CheckBelongAppBaseDir(filepath)) {
367 return true;
368 } else {
369 REQUEST_HILOGE("File dir not include base dir");
370 return false;
371 }
372 }
373
GetSandboxPath(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,const Config & config,std::string & path,std::vector<std::string> & pathVec)374 bool RequestAction::GetSandboxPath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config,
375 std::string &path, std::vector<std::string> &pathVec)
376 {
377 if (!StandardizePath(context, config, path)) {
378 REQUEST_HILOGE("StandardizePath Err");
379 return false;
380 };
381 if (!WholeToNormal(path, pathVec) || pathVec.empty()) {
382 REQUEST_HILOGE("WholeToNormal Err");
383 return false;
384 };
385 std::string baseDir;
386 if (!CheckBelongAppBaseDir(path, baseDir)) {
387 REQUEST_HILOGE("CheckBelongAppBaseDir Err");
388 return false;
389 };
390 return true;
391 }
392
CheckDownloadFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,Config & config)393 bool RequestAction::CheckDownloadFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config)
394 {
395 std::string path = config.saveas;
396 std::vector<std::string> pathVec;
397 if (!GetSandboxPath(context, config, path, pathVec)) {
398 return false;
399 }
400 // pop filename.
401 pathVec.pop_back();
402 if (!CreateDirs(pathVec)) {
403 REQUEST_HILOGE("CreateDirs Err");
404 return false;
405 }
406 config.saveas = path;
407 return true;
408 }
409
InterceptData(const std::string & str,const std::string & in,std::string & out)410 bool RequestAction::InterceptData(const std::string &str, const std::string &in, std::string &out)
411 {
412 std::size_t position = in.find_last_of(str);
413 // when the str at last index, will error.
414 if (position == std::string::npos || position + 1 >= in.size()) {
415 return false;
416 }
417 out = std::string(in, position + 1);
418 return true;
419 }
420
StandardizeFileSpec(FileSpec & file)421 void RequestAction::StandardizeFileSpec(FileSpec &file)
422 {
423 if (file.filename.empty()) {
424 InterceptData("/", file.uri, file.filename);
425 }
426 // Does not have "contentType" field or API9 "type" empty.
427 if (!file.hasContentType) {
428 InterceptData(".", file.filename, file.type);
429 }
430 if (file.name.empty()) {
431 file.name = "file";
432 }
433 return;
434 }
435
IsPathValid(const std::string & filePath)436 bool RequestAction::IsPathValid(const std::string &filePath)
437 {
438 auto path = filePath.substr(0, filePath.rfind('/'));
439 char resolvedPath[PATH_MAX + 1] = { 0 };
440 if (path.length() > PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr
441 || strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
442 REQUEST_HILOGE("invalid file path!");
443 return false;
444 }
445 return true;
446 }
447
GetInternalPath(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,const Config & config,std::string & path)448 bool RequestAction::GetInternalPath(
449 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config, std::string &path)
450 {
451 std::string fileName;
452 std::string pattern = "internal://cache/";
453 size_t pos = path.find(pattern);
454 if (pos != 0) {
455 fileName = path;
456 } else {
457 fileName = path.substr(pattern.size(), path.size());
458 }
459 if (fileName.empty()) {
460 return false;
461 }
462 path = context->GetCacheDir();
463 if (path.empty()) {
464 REQUEST_HILOGE("internal to cache error");
465 return false;
466 }
467 path += "/" + fileName;
468 if (!IsPathValid(path)) {
469 REQUEST_HILOGE("IsPathValid error");
470 return false;
471 }
472 return true;
473 }
474
FindDir(const std::string & pathDir)475 bool RequestAction::FindDir(const std::string &pathDir)
476 {
477 std::error_code err;
478 return std::filesystem::exists(pathDir, err);
479 }
480
GetFdDownload(const std::string & path,const Config & config)481 ExceptionErrorCode RequestAction::GetFdDownload(const std::string &path, const Config &config)
482 {
483 // File is exist.
484 if (FindDir(path)) {
485 if (config.firstInit && !config.overwrite) {
486 return config.version == Version::API10 ? E_FILE_IO : E_FILE_PATH;
487 }
488 }
489
490 FILE *file = nullptr;
491 if (config.firstInit) {
492 file = fopen(path.c_str(), "w+");
493 } else {
494 file = fopen(path.c_str(), "a+");
495 }
496
497 if (file == nullptr) {
498 return E_FILE_IO;
499 }
500
501 int32_t ret = chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP);
502 if (ret != 0) {
503 REQUEST_HILOGE("download file chmod fail: %{public}d", ret);
504 };
505
506 int32_t retClose = fclose(file);
507 if (retClose != 0) {
508 REQUEST_HILOGE("download fclose fail: %{public}d", ret);
509 }
510 return E_OK;
511 }
512
CheckDownloadFile(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,Config & config)513 ExceptionErrorCode RequestAction::CheckDownloadFile(
514 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config)
515 {
516 ExceptionErrorCode ret;
517 if (IsUserFile(config.saveas)) {
518 if (config.version == Version::API9 || !config.overwrite) {
519 return E_PARAMETER_CHECK;
520 }
521 FileSpec file = { .uri = config.saveas, .isUserFile = true };
522 ret = CheckUserFileSpec(context, config, file, false);
523 if (ret == ExceptionErrorCode::E_OK) {
524 config.files.push_back(file);
525 }
526 return ret;
527 }
528 if (config.version == Version::API9) {
529 std::string path = config.saveas;
530 if (config.saveas.find('/') == 0) {
531 // API9 do not check.
532 } else if (!GetInternalPath(context, config, path)) {
533 return E_PARAMETER_CHECK;
534 }
535 config.saveas = path;
536 } else {
537 if (!CheckDownloadFilePath(context, config)) {
538 return E_PARAMETER_CHECK;
539 }
540 }
541 FileSpec file = { .uri = config.saveas, .isUserFile = false };
542 StandardizeFileSpec(file);
543 config.files.push_back(file);
544 ret = GetFdDownload(file.uri, config);
545 if (ret != ExceptionErrorCode::E_OK) {
546 return ret;
547 }
548 if (!PathControl::AddPathsToMap(config.saveas)) {
549 return ExceptionErrorCode::E_FILE_IO;
550 }
551 return ExceptionErrorCode::E_OK;
552 }
553
IsUserFile(const std::string & path)554 bool RequestAction::IsUserFile(const std::string &path)
555 {
556 return path.find("file://docs/") == 0 || path.find("file://media/") == 0;
557 }
558
CheckUserFileSpec(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,const Config & config,FileSpec & file,bool isUpload)559 ExceptionErrorCode RequestAction::CheckUserFileSpec(
560 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config, FileSpec &file, bool isUpload)
561 {
562 if (config.mode != Mode::FOREGROUND) {
563 return E_PARAMETER_CHECK;
564 }
565 if (isUpload) {
566 std::shared_ptr<Uri> uri = std::make_shared<Uri>(file.uri);
567 std::shared_ptr<AppExecFwk::DataAbilityHelper> dataAbilityHelper =
568 AppExecFwk::DataAbilityHelper::Creator(context, uri);
569 if (dataAbilityHelper == nullptr) {
570 REQUEST_HILOGE("dataAbilityHelper null");
571 return E_PARAMETER_CHECK;
572 }
573 file.fd = dataAbilityHelper->OpenFile(*uri, "r");
574 } else {
575 std::shared_ptr<AppFileService::ModuleFileUri::FileUri> fileUri =
576 std::make_shared<AppFileService::ModuleFileUri::FileUri>(file.uri);
577 std::string realPath = fileUri->GetRealPath();
578 if (config.firstInit) {
579 file.fd = open(realPath.c_str(), O_RDWR | O_TRUNC);
580 } else {
581 file.fd = open(realPath.c_str(), O_RDWR | O_APPEND);
582 }
583 }
584 if (file.fd < 0) {
585 REQUEST_HILOGE("Failed to open user file, fd: %{public}d", file.fd);
586 return E_FILE_IO;
587 }
588 fdsan_exchange_owner_tag(file.fd, 0, REQUEST_FDSAN_TAG);
589 StandardizeFileSpec(file);
590 return E_OK;
591 }
592
CheckPathIsFile(const std::string & path)593 bool RequestAction::CheckPathIsFile(const std::string &path)
594 {
595 std::error_code err;
596 if (!std::filesystem::exists(path, err)) {
597 return false;
598 }
599 if (std::filesystem::is_directory(path, err)) {
600 return false;
601 }
602 return true;
603 }
604
GetFdUpload(const std::string & path,const Config & config)605 ExceptionErrorCode RequestAction::GetFdUpload(const std::string &path, const Config &config)
606 {
607 if (!CheckPathIsFile(path)) {
608 return config.version == Version::API10 ? E_FILE_IO : E_FILE_PATH;
609 }
610 FILE *file = fopen(path.c_str(), "r");
611 if (file == nullptr) {
612 return config.version == Version::API10 ? E_FILE_IO : E_FILE_PATH;
613 }
614 REQUEST_HILOGD("upload file fopen ok");
615 int32_t ret = chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP);
616 if (ret != 0) {
617 REQUEST_HILOGE("upload file chmod fail: %{public}d", ret);
618 }
619 int32_t retClose = fclose(file);
620 if (retClose != 0) {
621 REQUEST_HILOGE("upload fclose fail: %{public}d", ret);
622 }
623 return E_OK;
624 }
625
CheckUploadFileSpec(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,Config & config,FileSpec & file)626 ExceptionErrorCode RequestAction::CheckUploadFileSpec(
627 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config, FileSpec &file)
628 {
629 ExceptionErrorCode ret;
630 file.isUserFile = false;
631 std::string path = file.uri;
632 if (config.version == Version::API9) {
633 if (!GetInternalPath(context, config, path)) {
634 return E_PARAMETER_CHECK;
635 }
636 } else {
637 std::vector<std::string> pathVec;
638 if (!GetSandboxPath(context, config, path, pathVec)) {
639 return E_PARAMETER_CHECK;
640 }
641 }
642 REQUEST_HILOGD("CheckUploadFileSpec path");
643 file.uri = path;
644 ret = GetFdUpload(path, config);
645 if (ret != E_OK) {
646 return ret;
647 }
648 if (!PathControl::AddPathsToMap(file.uri)) {
649 return E_FILE_IO;
650 }
651 StandardizeFileSpec(file);
652 return E_OK;
653 }
654
CheckUploadFiles(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,Config & config)655 ExceptionErrorCode RequestAction::CheckUploadFiles(
656 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config)
657 {
658 // need reconstruction.
659 ExceptionErrorCode ret;
660 for (auto &file : config.files) {
661 if (IsUserFile(file.uri)) {
662 file.isUserFile = true;
663 if (config.version == Version::API9) {
664 return E_PARAMETER_CHECK;
665 }
666 ret = CheckUserFileSpec(context, config, file, true);
667 if (ret != ExceptionErrorCode::E_OK) {
668 return ret;
669 }
670 StandardizeFileSpec(file);
671 continue;
672 }
673
674 ret = CheckUploadFileSpec(context, config, file);
675 if (ret != ExceptionErrorCode::E_OK) {
676 return ret;
677 }
678 }
679 return E_OK;
680 }
681
CheckUploadBodyFiles(const std::string & filePath,Config & config)682 ExceptionErrorCode RequestAction::CheckUploadBodyFiles(const std::string &filePath, Config &config)
683 {
684 size_t len = config.files.size();
685 if (config.multipart) {
686 len = 1;
687 }
688
689 for (size_t i = 0; i < len; i++) {
690 if (filePath.empty()) {
691 REQUEST_HILOGE("internal to cache error");
692 return E_PARAMETER_CHECK;
693 }
694 auto now = std::chrono::high_resolution_clock::now();
695 auto timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
696 std::string path = filePath + "/tmp_body_" + std::to_string(i) + "_" + std::to_string(timestamp);
697 if (!IsPathValid(path)) {
698 REQUEST_HILOGE("Upload IsPathValid error");
699 return E_PARAMETER_CHECK;
700 }
701 FILE *bodyFile = fopen(path.c_str(), "w+");
702 if (bodyFile == nullptr) {
703 return E_FILE_IO;
704 }
705 int32_t ret = chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP);
706 if (ret != 0) {
707 REQUEST_HILOGE("body chmod fail: %{public}d", ret);
708 };
709
710 bool setRes = PathControl::AddPathsToMap(path);
711 int32_t retClose = fclose(bodyFile);
712 if (retClose != 0) {
713 REQUEST_HILOGE("upload body fclose fail: %{public}d", ret);
714 }
715 if (!setRes) {
716 return E_FILE_IO;
717 }
718 config.bodyFileNames.push_back(path);
719 }
720 return E_OK;
721 }
722
SetDirsPermission(std::vector<std::string> & dirs)723 bool RequestAction::SetDirsPermission(std::vector<std::string> &dirs)
724 {
725 if (dirs.empty()) {
726 return true;
727 }
728 std::string newPath = "/data/storage/el2/base/.ohos/.request/.certs";
729 std::vector<std::string> dirElems;
730 StringSplit(newPath, '/', dirElems);
731 if (!CreateDirs(dirElems)) {
732 REQUEST_HILOGE("CreateDirs Error");
733 return false;
734 }
735
736 for (const auto &folderPath : dirs) {
737 fs::path folder = folderPath;
738 if (!(fs::exists(folder) && fs::is_directory(folder))) {
739 return false;
740 }
741 for (const auto &entry : fs::directory_iterator(folder)) {
742 fs::path path = entry.path();
743 std::string existfilePath = folder.string() + "/" + path.filename().string();
744 std::string newfilePath = newPath + "/" + path.filename().string();
745 if (!fs::exists(newfilePath)) {
746 fs::copy(existfilePath, newfilePath);
747 }
748 if (chmod(newfilePath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
749 REQUEST_HILOGD("File add OTH access Failed.");
750 }
751 if (!PathControl::AddPathsToMap(newfilePath)) {
752 REQUEST_HILOGE("Set path permission fail.");
753 return false;
754 }
755 }
756 }
757 if (!dirs.empty()) {
758 dirs.clear();
759 dirs.push_back(newPath);
760 }
761 return true;
762 }
763
CheckFilePath(Config & config)764 ExceptionErrorCode RequestAction::CheckFilePath(Config &config)
765 {
766 auto context = AbilityRuntime::Context::GetApplicationContext();
767 ExceptionErrorCode ret;
768 if (context == nullptr) {
769 REQUEST_HILOGE("AppContext is null.");
770 return E_FILE_IO;
771 }
772 if (config.action == Action::DOWNLOAD) {
773 ret = CheckDownloadFile(context, config);
774 if (ret != ExceptionErrorCode::E_OK) {
775 return ret;
776 }
777 } else {
778 ret = CheckUploadFiles(context, config);
779 if (ret != ExceptionErrorCode::E_OK) {
780 return ret;
781 }
782 std::string filePath = context->GetCacheDir();
783 ret = CheckUploadBodyFiles(filePath, config);
784 if (ret != ExceptionErrorCode::E_OK) {
785 return ret;
786 }
787 }
788 if (!SetDirsPermission(config.certsPath)) {
789 return ExceptionErrorCode::E_FILE_IO;
790 }
791 return ExceptionErrorCode::E_OK;
792 }
793
Create(TaskBuilder & builder,std::string & tid)794 int32_t RequestAction::Create(TaskBuilder &builder, std::string &tid)
795 {
796 auto ret = builder.build();
797 if (ret.second != ExceptionErrorCode::E_OK) {
798 return ret.second;
799 }
800 int32_t err = CheckFilePath(ret.first);
801 if (err != ExceptionErrorCode::E_OK) {
802 return err;
803 }
804
805 int32_t seq = RequestManager::GetInstance()->GetNextSeq();
806 REQUEST_HILOGD("Begin Create, seq: %{public}d", seq);
807 err = RequestManager::GetInstance()->Create(ret.first, seq, tid);
808 if (err == 0) {
809 std::lock_guard<std::mutex> lockGuard(taskMutex_);
810 taskMap_.emplace(tid, ret.first);
811 }
812 return err;
813 }
814
CreateTasks(std::vector<TaskBuilder> & builders,std::vector<TaskRet> & rets)815 ExceptionErrorCode RequestAction::CreateTasks(std::vector<TaskBuilder> &builders, std::vector<TaskRet> &rets)
816 {
817 std::vector<Config> configs;
818 size_t len = builders.size();
819 rets.resize(len, {
820 .code = ExceptionErrorCode::E_OTHER,
821 });
822 for (size_t i = 0; i < len; i++) {
823 auto ret = builders[i].build();
824 if (ret.second != ExceptionErrorCode::E_OK) {
825 rets[i].code = ret.second;
826 continue;
827 }
828 ExceptionErrorCode err = CheckFilePath(ret.first);
829 if (err != ExceptionErrorCode::E_OK) {
830 rets[i].code = err;
831 continue;
832 }
833 // If config is invalid, do not add it to configs.
834 configs.push_back(ret.first);
835 }
836 PathControl::InsureMapAcl();
837
838 std::vector<TaskRet> temp_rets;
839 ExceptionErrorCode ret = RequestManager::GetInstance()->CreateTasks(configs, temp_rets);
840 if (ret == ExceptionErrorCode::E_OK) {
841 size_t ret_index = 0;
842 size_t temp_index = 0;
843 std::lock_guard<std::mutex> lockGuard(taskMutex_);
844 while (ret_index < len) {
845 if (rets[ret_index].code != ExceptionErrorCode::E_OTHER) {
846 ++ret_index;
847 continue;
848 }
849 rets[ret_index] = temp_rets[temp_index];
850 if (rets[ret_index].code == ExceptionErrorCode::E_OK) {
851 taskMap_[rets[ret_index].tid] = configs[temp_index];
852 }
853 ++ret_index;
854 ++temp_index;
855 }
856 }
857 return ret;
858 }
859
RemoveFile(const std::string & filePath)860 void RequestAction::RemoveFile(const std::string &filePath)
861 {
862 auto removeFile = [filePath]() -> void {
863 std::remove(filePath.c_str());
864 return;
865 };
866 ffrt::submit(removeFile, {}, {}, ffrt::task_attr().name("Os_Request_Rm").qos(ffrt::qos_default));
867 }
868
RemoveDirsPermission(const std::vector<std::string> & dirs)869 void RequestAction::RemoveDirsPermission(const std::vector<std::string> &dirs)
870 {
871 for (const auto &folderPath : dirs) {
872 fs::path folder = folderPath;
873 for (const auto &entry : fs::directory_iterator(folder)) {
874 fs::path path = entry.path();
875 std::string filePath = folder.string() + "/" + path.filename().string();
876 PathControl::SubPathsToMap(filePath);
877 }
878 }
879 }
880
ClearTaskTemp(const std::string & tid)881 bool RequestAction::ClearTaskTemp(const std::string &tid)
882 {
883 Config config;
884 {
885 std::lock_guard<std::mutex> lockGuard(taskMutex_);
886 auto it = taskMap_.find(tid);
887 if (it == taskMap_.end()) {
888 REQUEST_HILOGD("Clear task tmp files, not in taskMap_");
889 return false;
890 }
891 config = it->second;
892 taskMap_.erase(it);
893 }
894
895 auto bodyFileNames = config.bodyFileNames;
896 for (auto &filePath : bodyFileNames) {
897 std::error_code err;
898 if (!std::filesystem::exists(filePath, err)) {
899 continue;
900 }
901 err.clear();
902 PathControl::SubPathsToMap(filePath);
903 RemoveFile(filePath);
904 }
905
906 // Reset Acl permission
907 for (auto &file : config.files) {
908 PathControl::SubPathsToMap(file.uri);
909 }
910
911 RemoveDirsPermission(config.certsPath);
912 return true;
913 }
914
Remove(const std::string & tid)915 int32_t RequestAction::Remove(const std::string &tid)
916 {
917 RequestAction::ClearTaskTemp(tid);
918 return RequestManager::GetInstance()->Remove(tid, Version::API10);
919 }
920
RemoveTasks(const std::vector<std::string> & tids,std::unordered_map<std::string,ExceptionErrorCode> & rets)921 ExceptionErrorCode RequestAction::RemoveTasks(
922 const std::vector<std::string> &tids, std::unordered_map<std::string, ExceptionErrorCode> &rets)
923 {
924 for (auto &tid : tids) {
925 RequestAction::ClearTaskTemp(tid);
926 }
927 rets.clear();
928 std::vector<ExceptionErrorCode> vec;
929 ExceptionErrorCode code = RequestManager::GetInstance()->RemoveTasks(tids, Version::API10, vec);
930 if (code != ExceptionErrorCode::E_OK) {
931 return code;
932 }
933 uint32_t len = static_cast<uint32_t>(tids.size());
934 for (uint32_t i = 0; i < len; i++) {
935 rets.insert_or_assign(tids[i], vec[i]);
936 }
937 return ExceptionErrorCode::E_OK;
938 }
939
940 } // namespace OHOS::Request