* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cj_initialize.h"
#include <algorithm>
#include <cstring>
#include <fcntl.h>
#include <filesystem>
#include <fstream>
#include <regex>
#include <sys/stat.h>
#include "cj_request_common.h"
#include "cj_request_task.h"
#include "constant.h"
#include "log.h"
#include "network_security_config.h"
#include "request_common.h"
#include "request_manager.h"
#include "sys_event.h"
#include "securec.h"
#include "file_uri.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::AbilityRuntime::Context;
using OHOS::Request::Action;
using OHOS::Request::ExceptionErrorCode;
using OHOS::Request::FileSpec;
using OHOS::Request::FormItem;
using OHOS::Request::Version;
using OHOS::Request::SysEventLog;
using OHOS::Request::FAULT_EVENT;
using OHOS::Request::STATISTIC_EVENT;
using OHOS::Request::DfxErrorCode;
using OHOS::Request::VISIBILITY_COMPLETION;
using OHOS::Request::VISIBILITY_PROGRESS;
static constexpr uint32_t URL_MAXIMUM = 8192;
static constexpr uint32_t TITLE_MAXIMUM = 256;
static constexpr uint32_t DESCRIPTION_MAXIMUM = 1024;
static constexpr uint32_t MAX_UPLOAD_FILES = 100;
static constexpr uint32_t FILE_PERMISSION = 0644;
static const mode_t WRITE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
static const mode_t READ_MODE = S_IRUSR | S_IWUSR | S_IRGRP;
std::string GetHostnameFromURL(const std::string &url)
{
if (url.empty()) {
return "";
}
std::string delimiter = "://";
std::string tempUrl = url;
std::replace(tempUrl.begin(), tempUrl.end(), '\\', '/');
size_t posStart = tempUrl.find(delimiter);
if (posStart != std::string::npos) {
posStart += delimiter.length();
} else {
posStart = 0;
}
size_t notSlash = tempUrl.find_first_not_of('/', posStart);
if (notSlash != std::string::npos) {
posStart = notSlash;
}
size_t posEnd =
std::min({ tempUrl.find(':', posStart), tempUrl.find('/', posStart), tempUrl.find('?', posStart) });
if (posEnd != std::string::npos) {
return tempUrl.substr(posStart, posEnd - posStart);
}
return tempUrl.substr(posStart);
}
ExceptionError CJInitialize::ParseBundleName(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
std::string &bundleName)
{
ExceptionError err;
if (context->GetApplicationInfo() == nullptr) {
err.code = ExceptionErrorCode::E_OTHER;
err.errInfo = "ApplicationInfo is null";
return err;
}
bundleName = context->GetBundleName();
return err;
}
bool CJInitialize::ParseUrl(std::string &url, std::string &errInfo)
{
if (url.size() > URL_MAXIMUM) {
REQUEST_HILOGE("The URL exceeds the maximum length of 8192");
errInfo = "Parameter verification failed, the length of url exceeds 8192";
return false;
}
if (!CheckApiVersionAfter19()) {
if (!std::regex_match(url, std::regex("^http(s)?:\\/\\/.+"))) {
REQUEST_HILOGE("ParseUrl error");
return false;
}
} else {
auto hostname = GetHostnameFromURL(url);
bool cleartextPermitted = true;
OHOS::NetManagerStandard::NetworkSecurityConfig::GetInstance().IsCleartextPermitted(hostname,
cleartextPermitted);
if (!cleartextPermitted) {
if (!regex_match(url, std::regex("^https:\\/\\/.+"))) {
REQUEST_HILOGE("ParseUrl error");
errInfo = "Parameter verification failed, clear text transmission to this url is not permitted";
return false;
}
} else {
if (!regex_match(url, std::regex("^http(s)?:\\/\\/.+"))) {
REQUEST_HILOGE("ParseUrl error");
errInfo = "Parameter verification failed, the url should start with http(s)://";
return false;
}
}
}
return true;
}
bool CJInitialize::ParseCertsPath(std::string &url, std::vector<std::string> &certsPath, std::string &errInfo)
{
if (url.size() > URL_MAXIMUM) {
REQUEST_HILOGE("The URL exceeds the maximum length of 8192");
errInfo = "Parameter verification failed, the length of url exceeds 8192";
return false;
}
if (!regex_match(url, std::regex("^http(s)?:\\/\\/.+"))) {
REQUEST_HILOGE("ParseUrl error");
errInfo = "Parameter verification failed, the url should start with http(s)://";
return false;
}
typedef std::string::const_iterator iter_t;
iter_t urlEnd = url.end();
iter_t protocolStart = url.cbegin();
iter_t protocolEnd = std::find(protocolStart, urlEnd, ':');
std::string protocol = std::string(protocolStart, protocolEnd);
if (protocol != "https") {
REQUEST_HILOGD("Using Http");
return true;
}
if (protocolEnd != urlEnd) {
std::string afterProtocol = &*(protocolEnd);
if ((afterProtocol.length() > 3) && (afterProtocol.substr(0, 3) == "://")) {
protocolEnd += 3;
} else {
protocolEnd = url.cbegin();
}
} else {
protocolEnd = url.cbegin();
}
iter_t hostStart = protocolEnd;
iter_t pathStart = std::find(hostStart, urlEnd, '/');
iter_t queryStart = std::find(url.cbegin(), urlEnd, '?');
iter_t hostEnd = std::find(protocolEnd, (pathStart != urlEnd) ? pathStart : queryStart, ':');
std::string hostname = std::string(hostStart, hostEnd);
REQUEST_HILOGD("Hostname is %{public}s", hostname.c_str());
NetManagerStandard::NetworkSecurityConfig::GetInstance().GetTrustAnchorsForHostName(hostname, certsPath);
return true;
}
bool CJInitialize::Convert2FileSpec(const CFileSpec *cFile, const char *name, FileSpec &file)
{
file.name = name;
if (cFile->path == nullptr) {
return false;
}
file.uri = cFile->path;
if (file.uri.empty()) {
return false;
}
if (cFile->filename != nullptr) {
file.filename = cFile->filename;
}
if (cFile->mimeType != nullptr) {
file.type = cFile->mimeType;
}
return true;
}
bool CJInitialize::Convert2FileSpecs(const CFileSpecArr *cFiles, const char *name, std::vector<FileSpec> &files)
{
for (int i = 0; i < cFiles->size; ++i) {
FileSpec file;
if (!Convert2FileSpec(&cFiles->head[i], name, file)) {
return false;
}
files.push_back(file);
}
return true;
}
bool CJInitialize::ParseFormItems(const CFormItemArr *cForms, std::vector<FormItem> &forms,
std::vector<FileSpec> &files, std::string &errInfo)
{
for (int i = 0; i < cForms->size; ++i) {
CFormItem *cForm = &cForms->head[i];
if (cForm->value.str != nullptr) {
FormItem form;
form.name = cForm->name;
form.value = cForm->value.str;
forms.push_back(form);
} else if (cForm->value.file.path != nullptr) {
FileSpec file;
if (!Convert2FileSpec(&cForm->value.file, cForm->name, file)) {
REQUEST_HILOGE("Convert2FileSpec failed");
return false;
}
files.push_back(file);
} else if (cForm->value.files.size > 0) {
if (!Convert2FileSpecs(&cForm->value.files, cForm->name, files)) {
return false;
}
} else {
REQUEST_HILOGE("value type is error");
return false;
}
}
if (CheckApiVersionAfter19() && files.empty()) {
errInfo = "Missing mandatory parameters, files is empty";
return false;
}
return true;
}
bool CJInitialize::ParseData(const CConfig *config, Config &out, std::string &errInfo)
{
if (config->data.str == nullptr && config->data.formItems.size <= 0) {
return true;
}
if (out.action == Action::UPLOAD && config->data.formItems.size > 0) {
return ParseFormItems(&config->data.formItems, out.forms, out.files, errInfo);
} else if (out.action == Action::DOWNLOAD && config->data.str != nullptr) {
out.data = config->data.str;
} else {
REQUEST_HILOGE("data type is error");
errInfo = "Incorrect parameter type, the config.data parameter type is incorrect";
return false;
}
return true;
}
bool CJInitialize::ParseIndex(Config &config, std::string &errInfo)
{
if (config.action == Action::DOWNLOAD) {
config.index = 0;
return true;
}
if (config.files.size() <= config.index) {
REQUEST_HILOGE("files.size is %{public}zu, index is %{public}d", config.files.size(), config.index);
errInfo = "Parameter verification failed, config.index exceeds file list";
return false;
}
return true;
}
int64_t CJInitialize::ParseBegins(int64_t &begins)
{
return begins >= 0 ? begins : 0;
}
bool CJInitialize::ParseTitle(Config &config, std::string &errInfo)
{
if (config.title.size() > TITLE_MAXIMUM) {
errInfo = "Parameter verification failed, the length of config title exceeds 256";
return false;
}
if (config.title.empty()) {
config.title = config.action == Action::UPLOAD ? "upload" : "download";
}
return true;
}
bool CJInitialize::ParseToken(Config &config, std::string &errInfo)
{
if (config.token.empty()) {
config.token = "null";
return true;
}
size_t len = config.token.length();
if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
errInfo = "Parameter verification failed, the length of token should between 8 and 2048 bytes";
return false;
}
if (CheckApiVersionAfter19()) {
config.token = std::string(config.token.c_str(), len);
} else {
config.token = SHA256(config.token.c_str(), len);
}
return true;
}
bool CJInitialize::ParseDescription(std::string &description, std::string &errInfo)
{
if (description.size() > DESCRIPTION_MAXIMUM) {
errInfo = "Parameter verification failed, the length of config.description exceeds 1024";
return false;
}
return true;
}
void CJInitialize::StringTrim(std::string &str)
{
if (str.empty()) {
return;
}
str.erase(0, str.find_first_not_of(" "));
str.erase(str.find_last_not_of(" ") + 1);
return;
}
bool CJInitialize::CheckBelongAppBaseDir(const std::string &filepath, std::string &baseDir)
{
if (!CJInitialize::GetAppBaseDir(baseDir)) {
return false;
}
if ((filepath.find(AREA1) == 0) || filepath.find(AREA2) == 0 || filepath.find(AREA5) == 0) {
return true;
} else {
REQUEST_HILOGE("File dir not include base dir: %{public}s, path dir: %{public}s",
baseDir.c_str(), filepath.c_str());
return false;
}
}
bool CJInitialize::ParseSaveas(Config &config, std::string &errInfo)
{
if (config.action != Action::DOWNLOAD) {
config.saveas = "";
return true;
}
std::string temp = config.saveas;
if (!CheckApiVersionAfter19()) {
if (temp.empty() || temp == "./") {
return InterceptData("/", config.url, config.saveas);
}
temp = std::string(temp, 0, temp.find_last_not_of(' ') + 1);
} else {
StringTrim(temp);
if (temp.empty() || temp == "./") {
bool result = InterceptData("/", config.url, config.saveas);
if (!result) {
errInfo = "Parameter verification failed, config.saveas parse error";
}
return result;
}
}
if (temp.size() == 0 || temp[temp.size() - 1] == '/') {
errInfo = "Parameter verification failed, config.saveas parse error";
return false;
}
config.saveas = temp;
return true;
}
void CJInitialize::ParseMethod(Config &config)
{
std::string method = config.method;
config.method = config.action == Action::UPLOAD ? "PUT" : "GET";
if (!method.empty()) {
transform(method.begin(), method.end(), method.begin(), ::toupper);
if (config.action == Action::UPLOAD && (method == "POST" || method == "PUT")) {
config.method = method;
}
if (config.action == Action::DOWNLOAD && (method == "POST" || method == "GET")) {
config.method = method;
}
}
}
void CJInitialize::ParseNetwork(Network &network)
{
if (network != Network::ANY && network != Network::WIFI && network != Network::CELLULAR) {
network = Network::ANY;
}
}
void CJInitialize::ParseBackGround(Mode mode, bool &background)
{
background = mode == Mode::BACKGROUND;
}
void CJInitialize::ParseCertificatePins(std::string &url, std::string &certificatePins)
{
auto hostname = GetHostnameFromURL(url);
if (OHOS::NetManagerStandard::NetworkSecurityConfig::GetInstance().IsPinOpenMode(hostname)) {
REQUEST_HILOGI("Pins is openMode");
return;
}
auto ret =
OHOS::NetManagerStandard::NetworkSecurityConfig::GetInstance().GetPinSetForHostName(hostname, certificatePins);
if (ret != 0 || certificatePins.empty()) {
REQUEST_HILOGD("Get No pin set by hostname");
}
}
void CJInitialize::ParseGauge(Config &config)
{
if (config.gauge) {
config.notification.visibility = VISIBILITY_COMPLETION | VISIBILITY_PROGRESS;
} else {
config.notification.visibility = VISIBILITY_COMPLETION;
}
}
void CJInitialize::StringSplit(const std::string &str, const char delim, std::vector<std::string> &elems)
{
std::stringstream stream(str);
std::string item;
while (std::getline(stream, item, delim)) {
if (!item.empty()) {
elems.push_back(item);
}
}
return;
}
bool CJInitialize::GetBaseDir(std::string &baseDir)
{
auto context = OHOS::AbilityRuntime::Context::GetApplicationContext();
if (context == nullptr) {
REQUEST_HILOGE("AppContext is null.");
return false;
}
baseDir = context->GetBaseDir();
if (baseDir.empty()) {
REQUEST_HILOGE("Base dir not found.");
return false;
}
return true;
}
bool CJInitialize::CheckPathBaseDir(const std::string &filepath, std::string &baseDir)
{
if (!CJInitialize::GetBaseDir(baseDir)) {
return false;
}
if ((filepath.find(AREA1) == 0) || filepath.find(AREA2) == 0 || filepath.find(AREA5) == 0) {
return true;
}
REQUEST_HILOGE("File dir not include base dir: %{public}s", baseDir.c_str());
return false;
}
bool CJInitialize::CreateDirs(const std::vector<std::string> &pathDirs)
{
std::string path;
for (auto elem : pathDirs) {
path += "/" + elem;
std::error_code err;
if (std::filesystem::exists(path, err)) {
continue;
}
err.clear();
if (!std::filesystem::create_directory(path, err)) {
REQUEST_HILOGE("Create Dir Err: %{public}d, %{public}s", err.value(), err.message().c_str());
return false;
}
}
return true;
}
bool CJInitialize::CheckDownloadFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config,
std::string &errInfo)
{
std::string path = config.saveas;
if (!StandardizePath(context, config, path)) {
REQUEST_HILOGE("StandardizePath Err: %{public}s", path.c_str());
errInfo = "this is fail saveas path";
return false;
};
std::vector<std::string> pathVec;
if (!WholeToNormal(path, pathVec) || pathVec.empty()) {
REQUEST_HILOGE("WholeToNormal Err: %{public}s", path.c_str());
errInfo = "this is fail saveas path";
return false;
};
std::string baseDir;
if (!CheckPathBaseDir(path, baseDir)) {
REQUEST_HILOGE("CheckPathBaseDir Err: %{public}s", path.c_str());
errInfo = "this is fail saveas path";
return false;
};
pathVec.pop_back();
if (!CreateDirs(pathVec)) {
REQUEST_HILOGE("CreateDirs Err: %{public}s", path.c_str());
errInfo = "this is fail saveas path";
return false;
}
config.saveas = path;
return true;
}
bool CJInitialize::FileToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config,
std::string &path)
{
std::string bundleName = path.substr(0, path.find("/"));
if (bundleName != config.bundleName) {
REQUEST_HILOGE("path bundleName error.");
return false;
}
path.erase(0, bundleName.size());
return true;
}
bool CJInitialize::CacheToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, std::string &path)
{
std::string cache = context->GetCacheDir();
if (cache.empty()) {
REQUEST_HILOGE("GetCacheDir error.");
return false;
}
path = cache + "/" + path;
return true;
}
bool CJInitialize::StandardizePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config,
std::string &path)
{
std::string WHOLE_PREFIX = "/";
std::string FILE_PREFIX = "file://";
std::string INTERNAL_PREFIX = "internal://cache/";
std::string CURRENT_PREFIX = "./";
if (path.find(WHOLE_PREFIX) == 0) {
return true;
}
if (path.find(FILE_PREFIX) == 0) {
path.erase(0, FILE_PREFIX.size());
return FileToWhole(context, config, path);
}
if (path.find(INTERNAL_PREFIX) == 0) {
path.erase(0, INTERNAL_PREFIX.size());
return CacheToWhole(context, path);
}
if (path.find(CURRENT_PREFIX) == 0) {
path.erase(0, CURRENT_PREFIX.size());
return CacheToWhole(context, path);
}
return CacheToWhole(context, path);
}
bool CJInitialize::PathVecToNormal(const std::vector<std::string> &in, std::vector<std::string> &out)
{
for (auto elem : in) {
if (elem == "..") {
if (out.size() > 0) {
out.pop_back();
} else {
return false;
}
} else {
out.push_back(elem);
}
}
return true;
}
bool CJInitialize::WholeToNormal(std::string &path, std::vector<std::string> &out)
{
std::string normalPath;
std::vector<std::string> elems;
StringSplit(path, '/', elems);
if (!PathVecToNormal(elems, out)) {
return false;
}
for (auto elem : out) {
normalPath += "/" + elem;
}
path = normalPath;
return true;
}
ExceptionError CJInitialize::UploadBodyFileProc(std::string &fileName, Config &config)
{
ExceptionError err;
FILE* filePtr = fopen(fileName.c_str(), "r+");
if (filePtr == nullptr) {
filePtr = fopen(fileName.c_str(), "w+");
if (filePtr == nullptr) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "Failed to open file errno " + std::to_string(errno);
return err;
}
}
chmod(fileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
int32_t retClose = fclose(filePtr);
if (retClose != 0) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "Failed to close file errno " + std::to_string(errno);
return err;
}
config.bodyFileNames.push_back(fileName);
return err;
}
ExceptionError CJInitialize::UploadBodyFileProcV2(std::string &path, Config &config)
{
ExceptionError err;
FILE *bodyFile = fopen(path.c_str(), "w+");
if (bodyFile == NULL) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "UploadBodyFiles failed to open file errno " + std::to_string(errno);
SysEventLog::SendSysEventLog(FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_00, config.bundleName, "", err.errInfo);
return err;
}
int32_t ret = chmod(path.c_str(), WRITE_MODE);
if (ret != 0) {
REQUEST_HILOGE("body chmod fail: %{public}d", ret);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_01, config.bundleName, "", std::to_string(ret));
};
bool setRes = CJRequestTask::SetPathPermission(path, true);
int32_t retClose = fclose(bodyFile);
if (retClose != 0) {
REQUEST_HILOGE("upload body fclose fail: %{public}d", retClose);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_02, config.bundleName, "", std::to_string(retClose));
}
if (!setRes) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "UploadBodyFiles set body path permission fail";
return err;
}
config.bodyFileNames.push_back(path);
return err;
}
ExceptionError CJInitialize::CheckUploadBodyFiles(Config &config, const std::string &filePath)
{
size_t len = config.files.size();
ExceptionError err;
for (size_t i = 0; i < len; i++) {
if (filePath.empty()) {
REQUEST_HILOGE("internal to cache error");
err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
err.errInfo = "Parameter verification failed, UploadBodyFiles error empty path";
return err;
}
auto now = std::chrono::high_resolution_clock::now();
auto timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
std::string fileName = filePath + "/tmp_body_" + std::to_string(i) + "_" + std::to_string(timestamp);
REQUEST_HILOGD("Create upload body file, %{public}s", fileName.c_str());
if (!IsPathValid(fileName)) {
REQUEST_HILOGE("Upload IsPathValid error");
err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
err.errInfo = "Parameter verification failed, UploadBodyFiles error fail path";
return err;
}
if (!CheckApiVersionAfter19()) {
err = UploadBodyFileProc(fileName, config);
} else {
err = UploadBodyFileProcV2(fileName, config);
}
if (err.code != ExceptionErrorCode::E_OK) {
return err;
}
}
return err;
}
bool CJInitialize::InterceptData(const std::string &str, const std::string &in, std::string &out)
{
std::string tmpStr;
if (!CheckApiVersionAfter19()) {
tmpStr = std::string(in, 0, in.find_last_not_of(' ') + 1);
} else {
tmpStr = in;
}
std::size_t position = tmpStr.find_last_of(str);
if (position == std::string::npos || position + 1 >= tmpStr.size()) {
return false;
}
out = std::string(tmpStr, position + 1);
return true;
}
ExceptionError CJInitialize::GetFD(const std::string &path, const Config &config, int32_t &fd)
{
ExceptionError err;
fd = config.action == Action::UPLOAD ? open(path.c_str(), O_RDONLY) : open(path.c_str(), O_TRUNC | O_RDWR);
if (fd >= 0) {
REQUEST_HILOGD("File already exists");
if (config.action == Action::UPLOAD) {
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
close(fd);
return err;
} else {
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
}
if (config.overwrite) {
close(fd);
return err;
}
if (!config.firstInit) {
REQUEST_HILOGD("CJRequestTask config is not firstInit");
close(fd);
return err;
}
close(fd);
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "Download File already exists";
return err;
} else {
if (config.action == Action::UPLOAD) {
ExceptionErrorCode code = ExceptionErrorCode::E_FILE_IO;
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "Failed to open file errno " + std::to_string(errno);
return err;
}
fd = open(path.c_str(), O_CREAT | O_RDWR, FILE_PERMISSION);
if (fd < 0) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "Failed to open file errno " + std::to_string(errno);
return err;
}
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
close(fd);
}
return err;
}
bool CJInitialize::GetInternalPath(const std::string &fileUri,
const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config,
std::string &filePath)
{
if (config.action == Action::DOWNLOAD && fileUri.find('/') == 0) {
filePath = fileUri;
return true;
}
std::string fileName;
std::string pattern = "./";
size_t pos = fileUri.find(pattern);
if (pos != 0) {
fileName = fileUri;
} else {
fileName = fileUri.substr(pattern.size(), fileUri.size());
}
if (fileName.empty()) {
return false;
}
filePath = context->GetCacheDir();
if (filePath.empty()) {
REQUEST_HILOGE("internal to cache error");
return false;
}
filePath += "/" + fileName;
if (!IsPathValid(filePath)) {
REQUEST_HILOGE("IsPathValid error %{public}s", filePath.c_str());
return false;
}
return true;
}
ExceptionError CJInitialize::CheckFileSpec(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
Config &config)
{
ExceptionError err;
for (auto &file : config.files) {
std::string path;
if (!GetInternalPath(file.uri, context, config, path)) {
err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
err.errInfo = "this is fail path";
return err;
}
file.uri = path;
if (file.filename.empty()) {
InterceptData("/", file.uri, file.filename);
}
if (file.type.empty()) {
InterceptData(".", file.filename, file.type);
}
if (file.name.empty()) {
file.name = "file";
}
err = GetFD(path, config, file.fd);
if (err.code != ExceptionErrorCode::E_OK) {
return err;
}
if (!CJRequestTask::SetPathPermission(file.uri, config.action == Action::DOWNLOAD)) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "set path permission fail";
return err;
}
}
return err;
}
bool CJInitialize::GetAppBaseDir(std::string &baseDir)
{
auto context = AbilityRuntime::Context::GetApplicationContext();
if (context == nullptr) {
REQUEST_HILOGE("AppContext is null.");
SysEventLog::SendSysEventLog(FAULT_EVENT, DfxErrorCode::ABMS_FAULT_02, "AppContext is null");
return false;
}
baseDir = context->GetBaseDir();
if (baseDir.empty()) {
REQUEST_HILOGE("Base dir not found.");
SysEventLog::SendSysEventLog(FAULT_EVENT, DfxErrorCode::ABMS_FAULT_07, "Base dir not found");
return false;
}
return true;
}
ExceptionError CJInitialize::CheckFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
Config &config)
{
ExceptionError err;
if (config.action == Action::DOWNLOAD) {
if (!CheckDownloadFilePath(context, config, err.errInfo)) {
err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
return err;
}
FileSpec file = {.uri = config.saveas};
config.files.push_back(file);
}
err = CheckFileSpec(context, config);
if (err.code != ExceptionErrorCode::E_OK) {
return err;
}
if (!CJRequestTask::SetDirsPermission(config.certsPath)) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "set files of directors permission fail";
return err;
}
if (config.action == Action::UPLOAD) {
std::string filePath = context->GetCacheDir();
err = CheckUploadBodyFiles(config, filePath);
}
return err;
}
ExceptionError CJInitialize::CheckFilePathV2(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
Config &config)
{
ExceptionError err;
if (config.action == Action::DOWNLOAD) {
if (!CheckDownloadFile(context, config, err)) {
SysEventLog::SendSysEventLog(
STATISTIC_EVENT, DfxErrorCode::APP_ERROR_01, config.bundleName, "", err.errInfo);
return err;
}
} else {
if (!CheckUploadFiles(context, config, err)) {
SysEventLog::SendSysEventLog(
STATISTIC_EVENT, DfxErrorCode::APP_ERROR_01, config.bundleName, "", err.errInfo);
return err;
}
std::string filePath = context->GetCacheDir();
err = CheckUploadBodyFiles(config, filePath);
if (err.code != ExceptionErrorCode::E_OK) {
SysEventLog::SendSysEventLog(
STATISTIC_EVENT, DfxErrorCode::APP_ERROR_02, config.bundleName, "", err.errInfo);
return err;
}
}
if (!CJRequestTask::SetDirsPermission(config.certsPath)) {
err.code = ExceptionErrorCode::E_FILE_IO;
err.errInfo = "set files of directors permission fail";
SysEventLog::SendSysEventLog(FAULT_EVENT, DfxErrorCode::TASK_FAULT_02, config.bundleName, "", err.errInfo);
return err;
}
return err;
}
ExceptionError CJInitialize::ParseConfig(OHOS::AbilityRuntime::Context *stageContext, const CConfig *ffiConfig,
Config &config)
{
config.action = (OHOS::Request::Action)ffiConfig->action;
config.withErrCode = true;
config.version = Version::API10;
ExceptionError err;
if (stageContext == nullptr) {
err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
err.errInfo = "Get context fail";
return err;
}
std::shared_ptr<OHOS::AbilityRuntime::Context> context = stageContext->shared_from_this();
err = ParseBundleName(context, config.bundleName);
if (err.code != 0) {
return err;
}
err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
if (!ParseUrl(config.url, err.errInfo)) {
return err;
}
if (!ParseCertsPath(config.url, config.certsPath, err.errInfo)) {
return err;
}
if (!ParseData(ffiConfig, config, err.errInfo)) {
return err;
}
if (!ParseIndex(config, err.errInfo)) {
return err;
}
if (!ParseTitle(config, err.errInfo) || !ParseToken(config, err.errInfo)
|| !ParseDescription(config.description, err.errInfo)) {
return err;
}
if (!ParseSaveas(config, err.errInfo)) {
return err;
}
if (CheckApiVersionAfter19()) {
ParseCertificatePins(config.url, config.certificatePins);
ParseGauge(config);
}
ParseMethod(config);
ParseNetwork(config.network);
ParseBackGround(config.mode, config.background);
config.begins = ParseBegins(config.begins);
if (!CheckApiVersionAfter19()) {
err = CheckFilePath(context, config);
} else {
err = CheckFilePathV2(context, config);
}
return err;
}
bool CJInitialize::FindDir(const std::string &pathDir)
{
std::error_code err;
return std::filesystem::exists(pathDir, err);
}
bool CJInitialize::IsUserFile(const std::string &path)
{
return path.find("file://docs/") == 0 || path.find("file://media/") == 0;
}
bool CJInitialize::GetSandboxPath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config,
std::string &path, std::vector<std::string> &pathVec, std::string &errInfo)
{
if (!StandardizePath(context, config, path)) {
REQUEST_HILOGE("StandardizePath Err");
errInfo = "Parameter verification failed, GetSandboxPath failed, StandardizePath fail";
return false;
};
if (!WholeToNormal(path, pathVec) || pathVec.empty()) {
REQUEST_HILOGE("WholeToNormal Err");
errInfo = "Parameter verification failed, GetSandboxPath failed, WholeToNormal path fail";
return false;
};
std::string baseDir;
if (!CheckBelongAppBaseDir(path, baseDir)) {
REQUEST_HILOGE("CheckBelongAppBaseDir Err");
errInfo = "Parameter verification failed, GetSandboxPath failed, path not belong app base dir";
return false;
};
return true;
}
bool CJInitialize::CheckDownloadFile(
const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config, ExceptionError &error)
{
if (IsUserFile(config.saveas)) {
if (!config.overwrite) {
error.code = ExceptionErrorCode::E_PARAMETER_CHECK;
error.errInfo = "Parameter verification failed, download to user file must support overrite.";
return false;
}
FileSpec file = { .uri = config.saveas, .isUserFile = true };
if (!CheckUserFileSpec(context, config, file, error, false)) {
return false;
}
config.files.push_back(file);
return true;
}
if (!CheckDownloadFilePath(context, config, error.errInfo)) {
error.code = ExceptionErrorCode::E_PARAMETER_CHECK;
return false;
}
FileSpec file = { .uri = config.saveas, .isUserFile = false };
StandardizeFileSpec(file);
config.files.push_back(file);
if (!GetFdDownload(file.uri, config, error)) {
return false;
}
if (!CJRequestTask::SetPathPermission(config.saveas)) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "set path permission fail, download";
return false;
}
return true;
}
bool CJInitialize::CheckUserFileSpec(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
const Config &config, FileSpec &file, ExceptionError &error, bool isUpload)
{
if (config.mode != Mode::FOREGROUND) {
error.code = ExceptionErrorCode::E_PARAMETER_CHECK;
error.errInfo = "Parameter verification failed, user file can only for Mode::FOREGROUND";
return false;
}
if (isUpload) {
std::shared_ptr<Uri> uri = std::make_shared<Uri>(file.uri);
std::shared_ptr<AppExecFwk::DataAbilityHelper> dataAbilityHelper =
AppExecFwk::DataAbilityHelper::Creator(context, uri);
if (dataAbilityHelper == nullptr) {
REQUEST_HILOGE("dataAbilityHelper null");
error.code = ExceptionErrorCode::E_PARAMETER_CHECK;
error.errInfo = "Parameter verification failed, dataAbilityHelper null";
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::ABMS_FAULT_07, config.bundleName, "", error.errInfo);
return false;
}
file.fd = dataAbilityHelper->OpenFile(*uri, "r");
} else {
std::shared_ptr<AppFileService::ModuleFileUri::FileUri> fileUri =
std::make_shared<AppFileService::ModuleFileUri::FileUri>(file.uri);
std::string realPath = fileUri->GetRealPath();
if (config.firstInit) {
file.fd = open(realPath.c_str(), O_RDWR | O_TRUNC);
} else {
file.fd = open(realPath.c_str(), O_RDWR | O_APPEND);
}
}
if (file.fd < 0) {
REQUEST_HILOGE("Failed to open user file, fd: %{public}d", file.fd);
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "Failed to open user file";
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::ABMS_FAULT_09, config.bundleName, "", error.errInfo);
return false;
}
fdsan_exchange_owner_tag(file.fd, 0, OHOS::Request::REQUEST_FDSAN_TAG);
StandardizeFileSpec(file);
return true;
}
bool CJInitialize::CheckUploadFiles(
const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config, ExceptionError &error)
{
if (config.files.size() > MAX_UPLOAD_FILES) {
error.code = ExceptionErrorCode::E_PARAMETER_CHECK;
error.errInfo = "Parameter verification failed, upload by multipart file so many";
return false;
}
for (auto &file : config.files) {
if (IsUserFile(file.uri)) {
file.isUserFile = true;
if (!CheckUserFileSpec(context, config, file, error, true)) {
return false;
}
StandardizeFileSpec(file);
continue;
}
if (!CheckUploadFileSpec(context, config, file, error)) {
return false;
}
}
return true;
}
bool CJInitialize::CheckUploadFileSpec(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config,
FileSpec &file, ExceptionError &error)
{
file.isUserFile = false;
std::string path = file.uri;
std::vector<std::string> pathVec;
if (!GetSandboxPath(context, config, path, pathVec, error.errInfo)) {
error.code = ExceptionErrorCode::E_PARAMETER_CHECK;
return false;
}
REQUEST_HILOGD("CheckUploadFileSpec path");
file.uri = path;
if (!GetFdUpload(path, config, error)) {
return false;
}
if (!CJRequestTask::SetPathPermission(file.uri)) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "set path permission fail";
return false;
}
StandardizeFileSpec(file);
return true;
}
bool CJInitialize::GetFdUpload(const std::string &path, const Config &config, ExceptionError &error)
{
if (!CJInitialize::CheckPathIsFile(path, error)) {
error.code = ExceptionErrorCode::E_FILE_IO;
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_03, config.bundleName, "", error.errInfo);
return false;
}
FILE *file = fopen(path.c_str(), "r");
if (file == NULL) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "GetFd failed to open file errno " + std::to_string(errno);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_00, config.bundleName, "", error.errInfo);
return false;
}
REQUEST_HILOGD("upload file fopen ok");
int32_t ret = chmod(path.c_str(), READ_MODE);
if (ret != 0) {
REQUEST_HILOGE("upload file chmod fail: %{public}d", ret);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_01, config.bundleName, "", std::to_string(ret));
}
int32_t retClose = fclose(file);
if (retClose != 0) {
REQUEST_HILOGE("upload fclose fail: %{public}d", retClose);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_02, config.bundleName, "", std::to_string(retClose));
}
return true;
}
bool CJInitialize::CheckPathIsFile(const std::string &path, ExceptionError &error)
{
std::error_code err;
if (!std::filesystem::exists(path, err)) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "Path not exists: " + err.message();
SysEventLog::SendSysEventLog(FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_03, error.errInfo);
return false;
}
if (std::filesystem::is_directory(path, err)) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "Path not File: " + err.message();
SysEventLog::SendSysEventLog(FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_04, error.errInfo);
return false;
}
return true;
}
void CJInitialize::StandardizeFileSpec(FileSpec &file)
{
if (file.filename.empty()) {
InterceptData("/", file.uri, file.filename);
}
if (!file.hasContentType) {
InterceptData(".", file.filename, file.type);
}
if (file.name.empty()) {
file.name = "file";
}
return;
}
bool CJInitialize::GetFdDownload(const std::string &path, const Config &config, ExceptionError &error)
{
if (CJInitialize::FindDir(path)) {
if (config.firstInit && !config.overwrite) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "GetFd File exists and other error";
SysEventLog::SendSysEventLog(
STATISTIC_EVENT, DfxErrorCode::APP_ERROR_00, config.bundleName, "", error.errInfo);
return false;
}
}
FILE *file = NULL;
if (config.firstInit) {
file = fopen(path.c_str(), "w+");
} else {
file = fopen(path.c_str(), "a+");
}
if (file == NULL) {
error.code = ExceptionErrorCode::E_FILE_IO;
error.errInfo = "GetFd failed to open file errno " + std::to_string(errno);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_00, config.bundleName, "", error.errInfo);
return false;
}
int32_t ret = chmod(path.c_str(), WRITE_MODE);
if (ret != 0) {
REQUEST_HILOGE("download file chmod fail: %{public}d", ret);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_01, config.bundleName, "", std::to_string(ret));
};
int32_t retClose = fclose(file);
if (retClose != 0) {
REQUEST_HILOGE("download fclose fail: %{public}d", retClose);
SysEventLog::SendSysEventLog(
FAULT_EVENT, DfxErrorCode::STANDARD_FAULT_02, config.bundleName, "", std::to_string(retClose));
}
return true;
}
}