• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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