cj ffi init

Signed-off-by: zhoujing <zhoujing106@huawei.com>
Change-Id: Ib9947bd319b3af2551ea86bb181ebea988c3e9b0
This commit is contained in:
zhoujing 2024-04-23 20:00:29 +08:00 committed by zj94
parent b0f38c02b1
commit 2c41169d3f
24 changed files with 2896 additions and 2 deletions

View File

@ -50,7 +50,8 @@
"netstack",
"ylong_runtime",
"storage_service",
"ffrt"
"ffrt",
"openssl"
],
"third_party": [
"curl",
@ -61,7 +62,8 @@
"build": {
"group_type": {
"base_group": [
"//base/request/request/frameworks/js/napi:request"
"//base/request/request/frameworks/js/napi:request",
"//base/request/request/frameworks/cj/ffi:cj_request_ffi"
],
"fwk_group": [
"//base/request/request/frameworks/native:request_native"
@ -81,6 +83,15 @@
],
"header_base": "//base/request/request/interfaces/inner_kits/running_count/include"
}
},
{
"name": "//base/request/request/frameworks/cj/ffi:cj_request_ffi",
"header": {
"header_files": [
"cj_request_ffi.h"
],
"header_base": "//base/request/request/frameworks/cj/ffi/include"
}
}
],
"test": [

View File

@ -0,0 +1,88 @@
# 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.
import("//build/ohos.gni")
ohos_shared_library("cj_request_ffi") {
sanitize = {
integer_overflow = true
ubsan = true
boundary_sanitize = true
cfi = true
cfi_cross_dso = true
debug = false
}
stack_protector_ret = true
if (!defined(defines)) {
defines = []
}
include_dirs = [
"include",
"../../native/include",
"../../js/napi/include",
]
if (product_name != "ohos-sdk") {
deps = [
"../../../common:request_common_static",
"../../native:request_native",
]
external_deps = [
"ability_base:zuri",
"ability_runtime:abilitykit_native",
"ability_runtime:app_context",
"ability_runtime:data_ability_helper",
"ability_runtime:napi_base_context",
"c_utils:utils",
"ffrt:libffrt",
"hilog:libhilog",
"ipc:ipc_single",
"napi:ace_napi",
"napi:cj_bind_ffi",
"napi:cj_bind_native",
"netmanager_base:net_conn_manager_if",
"openssl:libssl_shared",
"storage_service:storage_manager_acl",
]
sources = [
"src/cj_app_state_callback.cpp",
"src/cj_initialize.cpp",
"src/cj_listener_list.cpp",
"src/cj_notify_data_listener.cpp",
"src/cj_request_common.cpp",
"src/cj_request_event.cpp",
"src/cj_request_ffi.cpp",
"src/cj_request_impl.cpp",
"src/cj_request_task.cpp",
"src/cj_response_listener.cpp",
]
} else {
defines += [ "PREVIEWER" ]
sources = [ "src/request_mock.cpp" ]
}
if (current_os == "ohos") {
defines += [ "OHOS_PLATFORM" ]
}
if (current_os == "mingw") {
defines += [ "WINDOWS_PLATFORM" ]
}
subsystem_name = "request"
part_name = "request"
}

View File

@ -0,0 +1,61 @@
/*
* 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.
*/
#ifndef OH_CJ_REQUEST_APP_STATE_CALLBACK_H
#define OH_CJ_REQUEST_APP_STATE_CALLBACK_H
#include "application_context.h"
namespace OHOS::CJSystemapi::Request {
class CJAppStateCallback : public OHOS::AbilityRuntime::AbilityLifecycleCallback {
public:
void OnAbilityCreate(const std::shared_ptr<NativeReference> &ability) override{};
void OnWindowStageCreate(
const std::shared_ptr<NativeReference> &ability, const std::shared_ptr<NativeReference> &windowStage) override
{
}
void OnWindowStageDestroy(
const std::shared_ptr<NativeReference> &ability, const std::shared_ptr<NativeReference> &windowStage) override
{
}
void OnWindowStageActive(
const std::shared_ptr<NativeReference> &ability, const std::shared_ptr<NativeReference> &windowStage) override
{
}
void OnWindowStageInactive(
const std::shared_ptr<NativeReference> &ability, const std::shared_ptr<NativeReference> &windowStage) override
{
}
void OnAbilityDestroy(const std::shared_ptr<NativeReference> &ability) override
{
}
void OnAbilityForeground(const std::shared_ptr<NativeReference> &ability) override;
void OnAbilityBackground(const std::shared_ptr<NativeReference> &ability) override
{
}
void OnAbilityContinue(const std::shared_ptr<NativeReference> &ability) override
{
}
};
} // OHOS::CJSystemapi::Request
#endif

View File

@ -0,0 +1,85 @@
/*
* 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.
*/
#ifndef OH_CJ_INITIALIZE_H
#define OH_CJ_INITIALIZE_H
#include <vector>
#include "ability.h"
#include "directory_ex.h"
#include "constant.h"
#include "js_common.h"
#include "napi_base_context.h"
#include "cj_request_ffi.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::ExceptionError;
using OHOS::Request::Config;
using OHOS::Request::FormItem;
using OHOS::Request::FileSpec;
using OHOS::Request::Action;
using OHOS::Request::Network;
using OHOS::Request::Mode;
using OHOS::AbilityRuntime::Context;
class CJInitialize {
public:
CJInitialize() = default;
~CJInitialize() = default;
static void StringSplit(const std::string &str, const char delim, std::vector<std::string> &elems);
static bool GetBaseDir(std::string &baseDir);
static ExceptionError ParseConfig(OHOS::AbilityRuntime::Context *context, const CConfig *ffiConfig, Config &config);
static ExceptionError ParseBundleName(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
std::string &config);
static bool ParseUrl(std::string &url);
static bool ParseCertsPath(std::string &url, std::vector<std::string> &certsPath);
static bool ParseFormItems(const CFormItemArr *cForms, std::vector<FormItem> &forms, std::vector<FileSpec> &files);
static bool ParseData(const CConfig *config, Config &out);
static bool Convert2FileSpec(const CFileSpec *cFile, const char *name, FileSpec &file);
static bool Convert2FileSpecs(const CFileSpecArr *cFiles, const char *name, std::vector<FileSpec> &files);
static bool ParseIndex(Config &config);
static int64_t ParseBegins(int64_t &begins);
static bool ParseTitle(Config &config);
static bool ParseToken(Config &config);
static bool ParseDescription(std::string &description);
static bool ParseSaveas(Config &config);
static void ParseMethod(Config &config);
static void ParseNetwork(Network &network);
static void ParseBackGround(Mode mode, bool &background);
static ExceptionError CheckFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config);
static bool CheckPathBaseDir(const std::string &filepath, std::string &baseDir);
static bool CreateDirs(const std::vector<std::string> &pathDirs);
static bool InterceptData(const std::string &str, const std::string &in, std::string &out);
static bool GetInternalPath(const std::string &fileUri,
const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config, std::string &filePath);
static ExceptionError GetFD(const std::string &path, const Config &config, int32_t &fd);
static bool FindDir(const std::string &pathDir);
private:
static bool CheckDownloadFilePath(
const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config, std::string &errInfo);
static bool StandardizePath(
const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config, std::string &path);
static bool CacheToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, std::string &path);
static bool FileToWhole(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const Config &config,
std::string &path);
static bool PathVecToNormal(const std::vector<std::string> &in, std::vector<std::string> &out);
static bool WholeToNormal(const std::string &wholePath, std::string &normalPath, std::vector<std::string> &out);
static ExceptionError CheckUploadBodyFiles(Config &config, const std::string &filePath);
static ExceptionError UploadBodyFileProc(std::string &fileName, Config &config);
};
} // OHOS::CJSystemapi::Request
#endif // CJ_INITIALIZE_H

View File

@ -0,0 +1,68 @@
/*
* 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.
*/
#ifndef OHOS_REQUEST_CJ_LISTENER_LIST_H
#define OHOS_REQUEST_CJ_LISTENER_LIST_H
#include <list>
#include <mutex>
#include <string>
#include <functional>
#include "js_common.h"
#include "cj_request_ffi.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::SubscribeType;
using OHOS::Request::ExceptionErrorCode;
using OHOS::Request::NotifyData;
using CFunc = void *;
using ProgressOnCallBackType = std::function<void(CProgress)>;
class ListenerList {
public:
ListenerList(const std::string &taskId, const SubscribeType &type)
: taskId_(taskId), type_(type)
{
}
bool HasListener();
struct CallBackInfo {
ProgressOnCallBackType cb_;
CFunc cbId_ = nullptr;
CallBackInfo(ProgressOnCallBackType cb_, CFunc cbId_)
: cb_(cb_), cbId_(cbId_) {}
};
protected:
bool IsListenerAdded(void *cb);
void OnMessageReceive(const std::shared_ptr<NotifyData> &notifyData);
void AddListenerInner(ProgressOnCallBackType &cb, CFunc cbId);
void RemoveListenerInner(CFunc cbId);
protected:
const std::string taskId_;
const SubscribeType type_;
std::recursive_mutex allCbMutex_;
std::list<std::pair<bool, std::shared_ptr<CallBackInfo>>> allCb_;
std::atomic<uint32_t> validCbNum{ 0 };
};
} // namespace OHOS::Request
#endif // OHOS_REQUEST_LISTENER_LIST_H

View File

@ -0,0 +1,48 @@
/*
* 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.
*/
#ifndef OHOS_REQUEST_CJ_NOTIFY_DATA_LISTENER_H
#define OHOS_REQUEST_CJ_NOTIFY_DATA_LISTENER_H
#include "i_notify_data_listener.h"
#include "cj_listener_list.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::INotifyDataListener;
using OHOS::Request::NotifyData;
using OHOS::Request::SubscribeType;
class CJNotifyDataListener
: public INotifyDataListener,
public ListenerList,
public std::enable_shared_from_this<CJNotifyDataListener> {
public:
CJNotifyDataListener(const std::string &taskId, const SubscribeType &type)
: ListenerList(taskId, type)
{
}
void AddListener(ProgressOnCallBackType cb, CFunc cbId);
void RemoveListener(CFunc cbId = nullptr);
void OnNotifyDataReceive(const std::shared_ptr<NotifyData> &notifyData) override;
private:
bool IsHeaderReceive(const std::shared_ptr<NotifyData> &notifyData);
void ProcessHeaderReceive(const std::shared_ptr<NotifyData> &notifyData);
void NotifyDataProcess(const std::shared_ptr<NotifyData> &notifyData);
};
} // namespace OHOS::Request
#endif // OHOS_REQUEST_JS_NOTIFY_DATA_LISTENER_H

View File

@ -0,0 +1,40 @@
/*
* 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.
*/
#ifndef OH_CJ_REQUEST_UTILS_H
#define OH_CJ_REQUEST_UTILS_H
#include <string>
#include <vector>
#include "constant.h"
#include "js_common.h"
#include "cj_request_ffi.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::Progress;
using OHOS::Request::ExceptionError;
void ReadBytesFromFile(const std::string &filePath, std::vector<uint8_t> &fileData);
char* MallocCString(const std::string& origin);
bool IsPathValid(const std::string &filePath);
std::string SHA256(const char *str, size_t len);
ExceptionError ConvertError(int32_t errorCode);
void RemoveFile(const std::string &filePath);
CProgress Convert2CProgress(const Progress &in);
} // namespace OHOS::CJSystemapi::Request
#endif

View File

@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef OHOS_REQUEST_CJ_EVENT_H
#define OHOS_REQUEST_CJ_EVENT_H
#include <string>
#include <unordered_set>
#include "cj_request_task.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::ExceptionErrorCode;
class CJRequestEvent final {
public:
CJRequestEvent() = default;
~CJRequestEvent() = default;
CJRequestEvent(CJRequestEvent const &) = delete;
void operator=(CJRequestEvent const &) = delete;
CJRequestEvent(CJRequestEvent &&) = delete;
CJRequestEvent &operator=(CJRequestEvent &&) = delete;
static ExceptionErrorCode Exec(std::string execType, const CJTask *task);
static SubscribeType StringToSubscribeType(const std::string &type);
private:
using Event = std::function<int32_t(const CJTask *)>;
static std::map<std::string, Event> requestEvent_;
static ExceptionErrorCode StartExec(const CJTask *task);
static ExceptionErrorCode StopExec(const CJTask *task);
static ExceptionErrorCode PauseExec(const CJTask *task);
static ExceptionErrorCode ResumeExec(const CJTask *task);
static std::map<std::string, SubscribeType> supportEventsV10_;
};
} // namespace OHOS::CJSystemapi::Request
#endif // OHOS_REQUEST_CJ_EVENT_H

View File

@ -0,0 +1,131 @@
/*
* 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.
*/
#ifndef OH_CJ_REQUEST_FFI_H
#define OH_CJ_REQUEST_FFI_H
#include <cstdint>
#ifndef FFI_EXPORT
#ifndef WINDOWS_PLATFORM
#define FFI_EXPORT __attribute__((visibility("default")))
#else
#define FFI_EXPORT __declspec(dllexport)
#endif
#endif
extern "C" {
typedef struct {
char *key;
char *value;
} CHashStrPair;
typedef struct {
CHashStrPair *headers;
int64_t size;
} CHashStrArr;
typedef struct {
char *path;
char *mimeType;
char *filename;
CHashStrArr extras;
} CFileSpec;
typedef struct {
CFileSpec *head;
int64_t size;
} CFileSpecArr;
typedef struct {
char *str;
CFileSpec file;
CFileSpecArr files;
} CFormItemValueTypeUion;
typedef struct {
char *name;
CFormItemValueTypeUion value;
} CFormItem;
typedef struct {
CFormItem *head;
int64_t size;
} CFormItemArr;
typedef struct {
char *str;
CFormItemArr formItems;
} CConfigDataTypeUion;
typedef struct {
int64_t action;
char *url;
char *title;
char *description;
int64_t mode;
bool overwrite;
char *method;
CHashStrArr headers;
CConfigDataTypeUion data;
char *saveas;
uint32_t network;
bool metered;
bool roaming;
bool retry;
bool redirect;
uint32_t index;
int64_t begins;
int64_t ends;
bool gauge;
bool precise;
char *token;
uint32_t priority;
CHashStrArr extras;
} CConfig;
typedef struct {
int32_t state;
uint32_t index;
int64_t processed;
int64_t *sizeArr;
int64_t sizeArrLen;
CHashStrArr extras;
} CProgress;
typedef struct {
int32_t errCode;
char *errMsg;
} RetError;
typedef struct {
int64_t instanceId;
int32_t taskId;
RetError err;
} RetReqData;
FFI_EXPORT void FfiOHOSRequestFreeTask(int32_t taskId);
FFI_EXPORT RetError FfiOHOSRequestTaskProgressOn(char *event, int32_t taskId, void (*callback)(CProgress progress));
FFI_EXPORT RetError FfiOHOSRequestTaskProgressOff(char *event, int32_t taskId, void *callback);
FFI_EXPORT RetError FfiOHOSRequestTaskStart(int32_t taskId);
FFI_EXPORT RetError FfiOHOSRequestTaskPause(int32_t taskId);
FFI_EXPORT RetError FfiOHOSRequestTaskResume(int32_t taskId);
FFI_EXPORT RetError FfiOHOSRequestTaskStop(int32_t taskId);
FFI_EXPORT RetReqData FfiOHOSRequestCreateTask(void* context, CConfig config);
FFI_EXPORT RetError FfiOHOSRequestRemoveTask(int32_t taskId);
}
#endif

View File

@ -0,0 +1,57 @@
/*
* 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.
*/
#ifndef OHOS_REQUEST_CJ_REQUEST_IMPL_H
#define OHOS_REQUEST_CJ_REQUEST_IMPL_H
#include <string>
#include <map>
#include "napi_base_context.h"
#include "cj_request_ffi.h"
#include "constant.h"
#include "js_common.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::ExceptionError;
using OHOS::Request::ExceptionErrorCode;
using OHOS::Request::Config;
class CJRequestImpl {
public:
CJRequestImpl() = default;
~CJRequestImpl() = default;
static RetReqData CreateTask(OHOS::AbilityRuntime::Context* context, CConfig *config);
static RetError RemoveTask(int32_t taskId);
static void FreeTask(int32_t taskId);
static RetError ProgressOn(char *event, int32_t taskId, void (*callback)(CProgress progress));
static RetError ProgressOff(char *event, int32_t taskId, void *callback);
static RetError TaskStart(int32_t taskId);
static RetError TaskPause(int32_t taskId);
static RetError TaskResume(int32_t taskId);
static RetError TaskStop(int32_t taskId);
static RetError Convert2RetErr(ExceptionErrorCode code);
static RetError Convert2RetErr(ExceptionError &err);
static std::map<std::string, std::string> ConvertCArr2Map(const CHashStrArr *cheaders);
static void Convert2Config(CConfig *config, Config &out);
private:
static RetError TaskExec(std::string execType, int32_t taskId);
};
} // namespace OHOS::CJSystemapi::Request
#endif // OHOS_REQUEST_JS_RESPONSE_LISTENER_H

View File

@ -0,0 +1,72 @@
/*
* 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.
*/
#ifndef OH_CJ_REQUEST_LOG_H
#define OH_CJ_REQUEST_LOG_H
#include "hilog/log.h"
#ifdef REQUEST_HILOGF
#undef REQUEST_HILOGF
#endif
#ifdef REQUEST_HILOGE
#undef REQUEST_HILOGE
#endif
#ifdef REQUEST_HILOGW
#undef REQUEST_HILOGW
#endif
#ifdef REQUEST_HILOGD
#undef REQUEST_HILOGD
#endif
#ifdef REQUEST_HILOGI
#undef REQUEST_HILOGI
#endif
#ifdef LOG_DOMAIN
#undef LOG_DOMAIN
#endif
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "CJ-Request"
#define LOG_DOMAIN 0xD001C50
#define MAKE_FILE_NAME (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
#define REQUEST_HILOGF(fmt, ...) \
HILOG_FATAL(LOG_CORE, "[%{public}s %{public}s %{public}d] " fmt, \
MAKE_FILE_NAME, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define REQUEST_HILOGE(fmt, ...) \
HILOG_ERROR(LOG_CORE, "[%{public}s %{public}s %{public}d] " fmt, \
MAKE_FILE_NAME, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define REQUEST_HILOGW(fmt, ...) \
HILOG_WARN(LOG_CORE, "[%{public}s %{public}s %{public}d] " fmt, \
MAKE_FILE_NAME, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define REQUEST_HILOGI(fmt, ...) \
HILOG_INFO(LOG_CORE, "[%{public}s %{public}s %{public}d] " fmt, \
MAKE_FILE_NAME, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define REQUEST_HILOGD(fmt, ...) \
HILOG_DEBUG(LOG_CORE, "[%{public}s %{public}s %{public}d] " fmt, \
MAKE_FILE_NAME, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif /* OH_CJ_REQUEST_LOG_H */

View File

@ -0,0 +1,86 @@
/*
* 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.
*/
#ifndef OH_CJ_REQUEST_TASK_H
#define OH_CJ_REQUEST_TASK_H
#include <cstdint>
#include <map>
#include <mutex>
#include <vector>
#include "ability_context.h"
#include "js_common.h"
#include "cj_notify_data_listener.h"
#include "cj_request_ffi.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::Config;
using OHOS::Request::Network;
using OHOS::Request::TaskInfo;
using OHOS::Request::NotifyData;
using OHOS::Request::Reason;
using OHOS::Request::DownloadErrorCode;
using OHOS::Request::ExceptionError;
using OHOS::Request::SubscribeType;
using OHOS::AbilityRuntime::Context;
class CJTask {
public:
CJTask();
~CJTask();
static ExceptionError Remove(const std::string &tid);
std::mutex listenerMutex_;
std::map<SubscribeType, std::shared_ptr<CJNotifyDataListener>> notifyDataListenerMap_;
Config config_;
int32_t taskId_{0};
static std::mutex taskMutex_;
static std::map<std::string, CJTask *> taskMap_;
static void AddTaskMap(const std::string &key, CJTask *task);
static CJTask* FindTaskById(int32_t taskId);
static CJTask* ClearTaskMap(const std::string &key);
static void ClearTaskTemp(const std::string &tid, bool isRmFiles, bool isRmAcls, bool isRmCertsAcls);
static std::mutex pathMutex_;
static std::map<std::string, int32_t> pathMap_;
static void AddPathMap(const std::string &filepath, const std::string &baseDir);
static void RemovePathMap(const std::string &filepath);
static void ResetDirAccess(const std::string &filepath);
static void RemoveDirsPermission(const std::vector<std::string> &dirs);
static bool register_;
static void RegisterForegroundResume();
static bool SetPathPermission(const std::string &filepath);
static bool SetDirsPermission(std::vector<std::string> &dirs);
std::string GetTidStr() const;
void SetTid();
ExceptionError Create(OHOS::AbilityRuntime::Context* context, Config &config);
ExceptionError On(std::string type, int32_t taskId, void (*callback)(CProgress progress));
ExceptionError Off(std::string event, CFunc callback);
static void ReloadListener();
private:
std::string tid_;
};
}
#endif

View File

@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef OHOS_REQUEST_CJ_RESPONSE_LISTENER_H
#define OHOS_REQUEST_CJ_RESPONSE_LISTENER_H
#include <list>
#include <mutex>
#include <string>
#include "i_response_listener.h"
namespace OHOS::CJSystemapi::Request {
class CJResponseListener
: public OHOS::Request::IResponseListener,
public std::enable_shared_from_this<CJResponseListener> {
public:
CJResponseListener(const std::string &taskId) : taskId_(taskId) {}
private:
const std::string taskId_;
};
} // namespace OHOS::CJSystemapi::Request
#endif // OHOS_REQUEST_JS_RESPONSE_LISTENER_H

View File

@ -0,0 +1,47 @@
/*
* 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_app_state_callback.h"
#include "js_common.h"
#include "cj_request_task.h"
#include "cj_request_log.h"
#include "request_manager.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::RequestManager;
using OHOS::Request::Mode;
void CJAppStateCallback::OnAbilityForeground(const std::shared_ptr<NativeReference> &ability)
{
if (RequestManager::GetInstance()->IsSaReady()) {
return;
}
for (auto task = CJTask::taskMap_.begin(); task != CJTask::taskMap_.end(); ++task) {
if (task->second->config_.mode == Mode::FOREGROUND) {
RequestManager::GetInstance()->LoadRequestServer();
return;
}
}
CJTask::register_ = false;
auto context = AbilityRuntime::ApplicationContext::GetInstance();
if (context == nullptr) {
REQUEST_HILOGE("Get ApplicationContext failed");
return;
}
context->UnregisterAbilityLifecycleCallback(std::make_shared<CJAppStateCallback>());
REQUEST_HILOGD("Unregister foreground resume callback success");
}
} // namespace OHOS::CJSystemapi::Request

View File

@ -0,0 +1,757 @@
/*
* 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 <regex>
#include <sys/stat.h>
#include <algorithm>
#include <cstring>
#include <filesystem>
#include <fcntl.h>
#include <fstream>
#include "securec.h"
#include "constant.h"
#include "js_common.h"
#include "cj_request_log.h"
#include "request_manager.h"
#include "cj_request_common.h"
#include "net_conn_client.h"
#include "cj_request_task.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::Action;
using OHOS::Request::Version;
using OHOS::Request::FileSpec;
using OHOS::Request::FormItem;
using OHOS::Request::ExceptionErrorCode;
using OHOS::AbilityRuntime::Context;
static constexpr uint32_t TOKEN_MAX_BYTES = 2048;
static constexpr uint32_t TOKEN_MIN_BYTES = 8;
static constexpr uint32_t URL_MAXIMUM = 2048;
static constexpr uint32_t TITLE_MAXIMUM = 256;
static constexpr uint32_t DESCRIPTION_MAXIMUM = 1024;
static constexpr uint32_t FILE_PERMISSION = 0644;
static const std::string AREA1 = "el1";
static const std::string AREA2 = "el2";
ExceptionError CJInitialize::ParseBundleName(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
std::string &bundleName)
{
if (context->GetApplicationInfo() == nullptr) {
return {
.code = ExceptionErrorCode::E_OTHER,
.errInfo = "ApplicationInfo is null"
};
}
bundleName = context->GetBundleName();
return {.code = ExceptionErrorCode::E_OK};
}
bool CJInitialize::ParseUrl(std::string &url)
{
if (url.size() > URL_MAXIMUM) {
REQUEST_HILOGE("The URL exceeds the maximum length of 2048");
return false;
}
if (!std::regex_match(url, std::regex("^http(s)?:\\/\\/.+"))) {
REQUEST_HILOGE("ParseUrl error");
return false;
}
return true;
}
bool CJInitialize::ParseCertsPath(std::string &url, std::vector<std::string> &certsPath)
{
if (url.size() > URL_MAXIMUM) {
REQUEST_HILOGE("The URL exceeds the maximum length of 2048");
return false;
}
if (!regex_match(url, std::regex("^http(s)?:\\/\\/.+"))) {
REQUEST_HILOGE("ParseUrl error");
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);
// 3 is the num of ://
if ((afterProtocol.length() > 3) && (afterProtocol.substr(0, 3) == "://")) {
// 3 means go beyound :// in protocolEnd
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::NetConnClient::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)
{
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;
}
}
return true;
}
bool CJInitialize::ParseData(const CConfig *config, Config &out)
{
REQUEST_HILOGD("formItems.size is %{public}lld, data.str is %{public}p", config->data.formItems.size,
config->data.str);
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);
} else if (out.action == Action::DOWNLOAD && config->data.str != nullptr) {
out.data = config->data.str;
} else {
REQUEST_HILOGE("data type is error");
return false;
}
return true;
}
bool CJInitialize::ParseIndex(Config &config)
{
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);
return false;
}
return true;
}
int64_t CJInitialize::ParseBegins(int64_t &begins)
{
return begins >= 0 ? begins : 0;
}
bool CJInitialize::ParseTitle(Config &config)
{
if (config.title.size() > TITLE_MAXIMUM) {
return false;
}
if (config.title.empty()) {
config.title = config.action == Action::UPLOAD ? "upload" : "download";
}
return true;
}
bool CJInitialize::ParseToken(Config &config)
{
if (config.token.empty()) {
config.token = "null";
return true;
}
size_t len = config.token.length();
if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
return false;
}
config.token = SHA256(config.token.c_str(), len);
return true;
}
bool CJInitialize::ParseDescription(std::string &description)
{
return description.size() <= DESCRIPTION_MAXIMUM;
}
bool CJInitialize::ParseSaveas(Config &config)
{
if (config.action != Action::DOWNLOAD) {
config.saveas = "";
return true;
}
std::string temp = config.saveas;
if (temp.empty() || temp == "./") {
return InterceptData("/", config.url, config.saveas);
}
temp = std::string(temp, 0, temp.find_last_not_of(' ') + 1);
if (temp[temp.size() - 1] == '/') {
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::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(baseDir) == 0) {
return true;
}
// check baseDir replaced with el2
if (baseDir.find(AREA1) != std::string::npos) {
baseDir = baseDir.replace(baseDir.find(AREA1), AREA1.length(), AREA2);
if (filepath.find(baseDir) == 0) {
return true;
}
REQUEST_HILOGE("File dir not include base dir: %{public}s", baseDir.c_str());
return false;
}
// check baseDir replaced with el1
if (baseDir.find(AREA2) != std::string::npos) {
baseDir = baseDir.replace(baseDir.find(AREA2), AREA2.length(), AREA1);
if (filepath.find(baseDir) == 0) {
return true;
}
REQUEST_HILOGE("File dir not include base dir: %{public}s", baseDir.c_str());
return false;
}
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();
// create_directory noexcept.
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::string normalPath;
std::vector<std::string> pathVec;
if (!WholeToNormal(path, normalPath, 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(normalPath, baseDir)) {
REQUEST_HILOGE("CheckPathBaseDir Err: %{public}s", normalPath.c_str());
errInfo = "this is fail saveas path";
return false;
};
// pop filename.
pathVec.pop_back();
if (!CreateDirs(pathVec)) {
REQUEST_HILOGE("CreateDirs Err: %{public}s", normalPath.c_str());
errInfo = "this is fail saveas path";
return false;
}
config.saveas = normalPath;
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(const std::string &wholePath, std::string &normalPath, std::vector<std::string> &out)
{
std::vector<std::string> elems;
StringSplit(wholePath, '/', elems);
if (!PathVecToNormal(elems, out)) {
return false;
}
for (auto elem : out) {
normalPath += "/" + elem;
}
return true;
}
ExceptionError CJInitialize::UploadBodyFileProc(std::string &fileName, Config &config)
{
int32_t bodyFd = open(fileName.c_str(), O_TRUNC | O_RDWR);
if (bodyFd < 0) {
bodyFd = open(fileName.c_str(), O_CREAT | O_RDWR, FILE_PERMISSION);
if (bodyFd < 0) {
return {
.code = ExceptionErrorCode::E_FILE_IO,
.errInfo = "Failed to open file errno " + std::to_string(errno)
};
}
}
if (bodyFd >= 0) {
chmod(fileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH);
}
config.bodyFds.push_back(bodyFd);
config.bodyFileNames.push_back(fileName);
return { .code = ExceptionErrorCode::E_OK };
}
ExceptionError CJInitialize::CheckUploadBodyFiles(Config &config, const std::string &filePath)
{
size_t len = config.files.size();
for (size_t i = 0; i < len; i++) {
if (filePath.empty()) {
REQUEST_HILOGE("internal to cache error");
return {
.code = ExceptionErrorCode::E_PARAMETER_CHECK,
.errInfo = "IsPathValid error empty path"
};
}
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("IsPathValid error %{public}s", fileName.c_str());
return {
.code = ExceptionErrorCode::E_PARAMETER_CHECK,
.errInfo = "IsPathValid error fail path"
};
}
ExceptionError ret = UploadBodyFileProc(fileName, config);
if (ret.code != ExceptionErrorCode::E_OK) {
return ret;
}
}
return { .code = ExceptionErrorCode::E_OK };
}
bool CJInitialize::InterceptData(const std::string &str, const std::string &in, std::string &out)
{
std::string tmpStr = std::string(in, 0, in.find_last_not_of(' ') + 1);
std::size_t position = tmpStr.find_last_of(str);
// when the str at last index, will error.
if (position == std::string::npos || position >= tmpStr.size() - 1) {
return false;
}
out = std::string(tmpStr, position + 1);
return true;
}
ExceptionError CJInitialize::GetFD(const std::string &path, const Config &config, int32_t &fd)
{
ExceptionError error = { .code = ExceptionErrorCode::E_OK };
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);
return error;
} else {
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH);
}
if (config.overwrite) {
return error;
}
if (!config.firstInit) {
REQUEST_HILOGD("CJTask config is not firstInit");
return error;
}
ExceptionErrorCode code = ExceptionErrorCode::E_FILE_IO;
return {
.code = code,
.errInfo = "Download File already exists"
};
} else {
if (config.action == Action::UPLOAD) {
ExceptionErrorCode code = ExceptionErrorCode::E_FILE_IO;
return {.code = code, .errInfo = "Failed to open file errno " + std::to_string(errno)};
}
fd = open(path.c_str(), O_CREAT | O_RDWR, FILE_PERMISSION);
if (fd < 0) {
return {.code = ExceptionErrorCode::E_FILE_IO, .errInfo = "Failed to open file errno " +
std::to_string(errno)};
}
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH);
}
return error;
}
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::CheckFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
Config &config)
{
ExceptionError err = { .code = ExceptionErrorCode::E_OK };
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);
}
for (auto &file : config.files) {
std::string path;
if (!GetInternalPath(file.uri, context, config, path)) {
return {
.code = ExceptionErrorCode::E_PARAMETER_CHECK,
.errInfo = "this is fail path"
};
}
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";
}
if (!CJTask::SetPathPermission(file.uri)) {
return {
.code = ExceptionErrorCode::E_FILE_IO,
.errInfo = "set path permission fail"
};
}
err = GetFD(path, config, file.fd);
if (err.code != ExceptionErrorCode::E_OK) {
return err;
}
}
if (!CJTask::SetDirsPermission(config.certsPath)) {
return {.code = ExceptionErrorCode::E_FILE_IO, .errInfo = "set files of directors permission fail"};
}
if (config.action == Action::UPLOAD) {
std::string filePath = context->GetCacheDir();
err = CheckUploadBodyFiles(config, filePath);
}
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; // CJ only support API10
if (stageContext == nullptr) {
return {
.code = ExceptionErrorCode::E_PARAMETER_CHECK,
.errInfo = "Get context fail"
};
}
std::shared_ptr<OHOS::AbilityRuntime::Context> context = stageContext->shared_from_this();
ExceptionError ret = ParseBundleName(context, config.bundleName);
if (ret.code != 0) {
return ret;
}
ret.code = ExceptionErrorCode::E_PARAMETER_CHECK;
if (!ParseUrl(config.url)) {
ret.errInfo = "parse url error";
return ret;
}
if (!ParseCertsPath(config.url, config.certsPath)) {
ret.errInfo = "parse certs path error";
return ret;
}
if (!ParseData(ffiConfig, config)) {
ret.errInfo = "parse data error";
return ret;
}
if (!ParseIndex(config)) {
ret.errInfo = "Index exceeds file list";
return ret;
}
if (!ParseTitle(config) ||
!ParseToken(config) ||
!ParseDescription(config.description)) {
ret.errInfo = "Exceeding maximum length";
return ret;
}
if (!ParseSaveas(config)) {
ret.errInfo = "parse saveas error";
return ret;
}
ParseMethod(config);
ParseNetwork(config.network);
ParseBackGround(config.mode, config.background);
config.begins = ParseBegins(config.begins);
return CheckFilePath(context, config);
}
bool CJInitialize::FindDir(const std::string &pathDir)
{
std::error_code err;
return std::filesystem::exists(pathDir, err);
}
} //namespace OHOS::CJSystemapi::Request

View File

@ -0,0 +1,91 @@
/*
* 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_listener_list.h"
#include "cj_request_common.h"
namespace OHOS::CJSystemapi::Request {
void ListenerList::AddListenerInner(ProgressOnCallBackType &cb, CFunc cbId)
{
std::lock_guard<std::recursive_mutex> lock(allCbMutex_);
if (this->IsListenerAdded(cbId)) {
return;
}
this->allCb_.push_back(std::make_pair(true, std::make_shared<CallBackInfo>(cb, cbId)));
++this->validCbNum;
}
void ListenerList::RemoveListenerInner(CFunc cb)
{
std::lock_guard<std::recursive_mutex> lock(allCbMutex_);
if (this->validCbNum == 0) {
return;
}
if (cb == nullptr) {
for (auto it = this->allCb_.begin(); it != this->allCb_.end(); it++) {
it->first = false;
}
this->validCbNum = 0;
return;
}
for (auto it = this->allCb_.begin(); it != this->allCb_.end(); it++) {
if (it->second->cbId_ == cb) {
if (it->first == true) {
it->first = false;
--this->validCbNum;
}
break;
}
}
}
void ListenerList::OnMessageReceive(const std::shared_ptr<NotifyData> &notifyData)
{
std::lock_guard<std::recursive_mutex> lock(allCbMutex_);
for (auto it = this->allCb_.begin(); it != this->allCb_.end();) {
if (it->first == false) {
it = this->allCb_.erase(it);
continue;
}
it->second->cb_(Convert2CProgress(notifyData->progress));
it++;
}
}
bool ListenerList::IsListenerAdded(void *cb)
{
if (cb == nullptr) {
return true;
}
for (auto it = this->allCb_.begin(); it != this->allCb_.end(); it++) {
if (it->second->cbId_ == cb) {
return it->first;
}
}
return false;
}
bool ListenerList::HasListener()
{
return this->validCbNum != 0;
}
} // namespace OHOS::Request

View File

@ -0,0 +1,112 @@
/*
* 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_notify_data_listener.h"
#include <numeric>
#include "cj_request_common.h"
#include "cj_request_task.h"
#include "cj_request_log.h"
#include "request_manager.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::RequestManager;
using OHOS::Request::Version;
using OHOS::Request::Action;
using OHOS::Request::State;
void CJNotifyDataListener::AddListener(ProgressOnCallBackType cb, CFunc cbId)
{
this->AddListenerInner(cb, cbId);
/* remove listener must be subscribed to free task */
if (this->validCbNum == 1 && this->type_ != SubscribeType::REMOVE) {
RequestManager::GetInstance()->AddListener(this->taskId_, this->type_, shared_from_this());
}
}
void CJNotifyDataListener::RemoveListener(CFunc cbId)
{
this->RemoveListenerInner(cbId);
if (this->validCbNum == 0 && this->type_ != SubscribeType::REMOVE) {
RequestManager::GetInstance()->RemoveListener(this->taskId_, this->type_, shared_from_this());
}
}
bool CJNotifyDataListener::IsHeaderReceive(const std::shared_ptr<NotifyData> &notifyData)
{
if (notifyData->version == Version::API10 && notifyData->action == Action::UPLOAD &&
notifyData->progress.state == State::COMPLETED &&
(notifyData->type == SubscribeType::PROGRESS || notifyData->type == SubscribeType::COMPLETED)) {
return true;
}
return false;
}
void CJNotifyDataListener::ProcessHeaderReceive(const std::shared_ptr<NotifyData> &notifyData)
{
CJTask *task = nullptr;
{
std::lock_guard<std::mutex> lockGuard(CJTask::taskMutex_);
auto item = CJTask::taskMap_.find(std::to_string(notifyData->taskId));
if (item == CJTask::taskMap_.end()) {
REQUEST_HILOGE("CJTask ID not found");
return;
}
task = item->second;
}
uint32_t index = notifyData->progress.index;
size_t len = task->config_.bodyFileNames.size();
if (index < len) {
std::string &filePath = task->config_.bodyFileNames[index];
ReadBytesFromFile(filePath, notifyData->progress.bodyBytes);
// Waiting for "complete" to read and delete.
if (!(notifyData->version == Version::API10 && index == len - 1 &&
notifyData->type == SubscribeType::PROGRESS)) {
RemoveFile(filePath);
}
}
}
void CJNotifyDataListener::NotifyDataProcess(const std::shared_ptr<NotifyData> &notifyData)
{
if (IsHeaderReceive(notifyData)) {
ProcessHeaderReceive(notifyData);
}
}
static void RemoveJSTask(const std::shared_ptr<NotifyData> &notifyData)
{
std::string tid = std::to_string(notifyData->taskId);
if (notifyData->version == Version::API10) {
if (notifyData->type == SubscribeType::REMOVE) {
CJTask::ClearTaskTemp(tid, true, true, true);
CJTask::ClearTaskMap(tid);
REQUEST_HILOGD("jstask %{public}s removed", tid.c_str());
} else if (notifyData->type == SubscribeType::COMPLETED || notifyData->type == SubscribeType::FAILED) {
CJTask::ClearTaskTemp(tid, true, false, false);
}
}
}
void CJNotifyDataListener::OnNotifyDataReceive(const std::shared_ptr<NotifyData> &notifyData)
{
this->NotifyDataProcess(notifyData);
this->OnMessageReceive(notifyData);
RemoveJSTask(notifyData);
}
} // namespace OHOS::Request

View File

@ -0,0 +1,160 @@
/*
* 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_request_common.h"
#include <cstdlib>
#include <sstream>
#include <fstream>
#include "ffrt.h"
#include "cj_request_log.h"
#include "securec.h"
#include "openssl/sha.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::ExceptionErrorCode;
void ReadBytesFromFile(const std::string &filePath, std::vector<uint8_t> &fileData)
{
// Ensure filePath validity.
std::ifstream inputFile(filePath.c_str(), std::ios::binary);
if (inputFile.is_open()) {
inputFile.seekg(0, std::ios::end);
fileData.resize(inputFile.tellg());
inputFile.seekg(0);
inputFile.read(reinterpret_cast<char *>(fileData.data()), fileData.size());
inputFile.close();
} else {
REQUEST_HILOGW("Read bytes from file, invalid file path!");
}
return;
}
char* MallocCString(const std::string& origin)
{
if (origin.empty()) {
return nullptr;
}
auto len = origin.length() + 1;
char* res = (char*)malloc(sizeof(char) * len);
if (res == nullptr) {
return nullptr;
}
return std::char_traits<char>::copy(res, origin.c_str(), len);
}
bool IsPathValid(const std::string &filePath)
{
auto path = filePath.substr(0, filePath.rfind('/'));
char resolvedPath[PATH_MAX + 1] = { 0 };
if (path.length() > PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr ||
strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
REQUEST_HILOGE("invalid file path!");
return false;
}
return true;
}
std::string SHA256(const char *str, size_t len)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str, len);
SHA256_Final(hash, &sha256);
std::stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
// 2 means setting hte width of the output.
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
}
return ss.str();
}
ExceptionError ConvertError(int32_t errorCode)
{
ExceptionError err{};
auto generateError = [&err](ExceptionErrorCode errorCode, const std::string &info) {
err.code = errorCode;
err.errInfo = info;
REQUEST_HILOGE("errorCode: %{public}d, errInfo: %{public}s", err.code, err.errInfo.c_str());
};
switch (errorCode) {
case ExceptionErrorCode::E_UNLOADING_SA:
generateError(ExceptionErrorCode::E_SERVICE_ERROR, "Service ability is quitting.");
break;
case ExceptionErrorCode::E_IPC_SIZE_TOO_LARGE:
generateError(ExceptionErrorCode::E_SERVICE_ERROR, "Ipc error.");
break;
case ExceptionErrorCode::E_MIMETYPE_NOT_FOUND:
generateError(ExceptionErrorCode::E_OTHER, "Mimetype not found.");
break;
case ExceptionErrorCode::E_TASK_INDEX_TOO_LARGE:
generateError(ExceptionErrorCode::E_TASK_NOT_FOUND, "Task index out of range.");
break;
default:
break;
}
return err;
}
CProgress Convert2CProgress(const Progress &in)
{
CProgress out = { 0 };
out.state = static_cast<int32_t>(in.state);
out.index = in.index;
out.processed = in.processed;
out.sizeArrLen = static_cast<int64_t>(in.sizes.size());
if (out.sizeArrLen > 0) {
out.sizeArr = static_cast<int64_t *>(malloc(sizeof(int64_t) * in.sizes.size()));
if (out.sizeArr == nullptr) {
return out;
}
for (std::vector<long>::size_type i = 0; i < in.sizes.size(); ++i) {
out.sizeArr[i] = in.sizes[i];
}
}
out.extras.size = static_cast<int64_t>(in.extras.size());
if (out.extras.size <= 0) {
return out;
}
out.extras.headers = static_cast<CHashStrPair *>(malloc(sizeof(CHashStrPair) * out.extras.size));
if (out.extras.headers == nullptr) {
return out;
}
int index = 0;
for (auto iter = in.extras.begin(); iter != in.extras.end(); ++iter) {
CHashStrPair *elem = &out.extras.headers[index++];
elem->key = MallocCString(iter->first);
elem->value = MallocCString(iter->second);
}
return out;
}
void RemoveFile(const std::string &filePath)
{
auto removeFile = [filePath]() -> void {
std::remove(filePath.c_str());
return;
};
ffrt::submit(removeFile, {}, {}, ffrt::task_attr().name("Os_Request_Rm").qos(ffrt::qos_default));
}
} //namespace OHOS::CJSystemapi::Request

View File

@ -0,0 +1,120 @@
/*
* 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_request_event.h"
#include "cj_request_log.h"
#include "request_manager.h"
#include "cj_initialize.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::Request::FUNCTION_PAUSE;
using OHOS::Request::FUNCTION_RESUME;
using OHOS::Request::FUNCTION_START;
using OHOS::Request::FUNCTION_STOP;
using OHOS::Request::Action;
using OHOS::Request::Config;
using OHOS::Request::FileSpec;
using OHOS::Request::RequestManager;
using OHOS::Request::Version;
static constexpr const char *EVENT_COMPLETED = "completed";
static constexpr const char *EVENT_FAILED = "failed";
static constexpr const char *EVENT_PAUSE = "pause";
static constexpr const char *EVENT_RESUME = "resume";
static constexpr const char *EVENT_REMOVE = "remove";
static constexpr const char *EVENT_PROGRESS = "progress";
static constexpr const char *EVENT_RESPONSE = "response";
std::map<std::string, SubscribeType> CJRequestEvent::supportEventsV10_ = {
{ EVENT_PROGRESS, SubscribeType::PROGRESS },
{ EVENT_COMPLETED, SubscribeType::COMPLETED },
{ EVENT_FAILED, SubscribeType::FAILED },
{ EVENT_PAUSE, SubscribeType::PAUSE },
{ EVENT_RESUME, SubscribeType::RESUME },
{ EVENT_REMOVE, SubscribeType::REMOVE },
{ EVENT_RESPONSE, SubscribeType::RESPONSE },
};
SubscribeType CJRequestEvent::StringToSubscribeType(const std::string &type)
{
if (supportEventsV10_.find(type) != supportEventsV10_.end()) {
return supportEventsV10_[type];
}
return SubscribeType::BUTT;
}
std::map<std::string, CJRequestEvent::Event> CJRequestEvent::requestEvent_ = {
{ FUNCTION_PAUSE, CJRequestEvent::PauseExec },
{ FUNCTION_RESUME, CJRequestEvent::ResumeExec },
{ FUNCTION_START, CJRequestEvent::StartExec },
{ FUNCTION_STOP, CJRequestEvent::StopExec },
};
ExceptionErrorCode CJRequestEvent::Exec(std::string execType, const CJTask *task)
{
auto handle = requestEvent_.find(execType);
if (handle == requestEvent_.end()) {
return ExceptionErrorCode::E_PARAMETER_CHECK;
}
return (ExceptionErrorCode)handle->second(task);
}
ExceptionErrorCode CJRequestEvent::StartExec(const CJTask *task)
{
REQUEST_HILOGD("RequestEvent::StartExec in");
Config config = task->config_;
// Rechecks file path.
if (config.files.size() == 0) {
return ExceptionErrorCode::E_FILE_IO;
}
FileSpec file = config.files[0];
if (CJInitialize::FindDir(file.uri) && config.action == Action::DOWNLOAD) {
REQUEST_HILOGD("Found the downloaded file: %{public}s.", file.uri.c_str());
if (chmod(file.uri.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH) != 0) {
REQUEST_HILOGD("File add OTH access Failed.");
}
if (!CJTask::SetPathPermission(file.uri)) {
REQUEST_HILOGE("Set path permission fail.");
return ExceptionErrorCode::E_FILE_IO;
}
}
return (ExceptionErrorCode)RequestManager::GetInstance()->Start(task->GetTidStr());
}
ExceptionErrorCode CJRequestEvent::StopExec(const CJTask *task)
{
return (ExceptionErrorCode)RequestManager::GetInstance()->Stop(task->GetTidStr());
}
ExceptionErrorCode CJRequestEvent::PauseExec(const CJTask *task)
{
return (ExceptionErrorCode)RequestManager::GetInstance()->Pause(task->GetTidStr(), Version::API10);
}
ExceptionErrorCode CJRequestEvent::ResumeExec(const CJTask *task)
{
if (!RequestManager::GetInstance()->LoadRequestServer()) {
return ExceptionErrorCode::E_SERVICE_ERROR;
}
return (ExceptionErrorCode)RequestManager::GetInstance()->Resume(task->GetTidStr());
}
} // namespace OHOS::CJSystemapi::Request

View File

@ -0,0 +1,71 @@
/*
* 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_request_ffi.h"
#include <cinttypes>
#include "cj_request_log.h"
#include "cj_request_task.h"
#include "cj_request_common.h"
#include "cj_request_impl.h"
namespace OHOS::CJSystemapi::Request {
extern "C" {
void FfiOHOSRequestFreeTask(int32_t taskId)
{
CJRequestImpl::FreeTask(taskId);
}
RetError FfiOHOSRequestTaskProgressOn(char *event, int32_t taskId, void (*callback)(CProgress progress))
{
return CJRequestImpl::ProgressOn(event, taskId, callback);
}
RetError FfiOHOSRequestTaskProgressOff(char *event, int32_t taskId, void *callback)
{
return CJRequestImpl::ProgressOff(event, taskId, callback);
}
RetError FfiOHOSRequestTaskStart(int32_t taskId)
{
return CJRequestImpl::TaskStart(taskId);
}
RetError FfiOHOSRequestTaskPause(int32_t taskId)
{
return CJRequestImpl::TaskPause(taskId);
}
RetError FfiOHOSRequestTaskResume(int32_t taskId)
{
return CJRequestImpl::TaskResume(taskId);
}
RetError FfiOHOSRequestTaskStop(int32_t taskId)
{
return CJRequestImpl::TaskStop(taskId);
}
RetReqData FfiOHOSRequestCreateTask(void* context, CConfig config)
{
return CJRequestImpl::CreateTask((OHOS::AbilityRuntime::Context *)context, &config);
}
RetError FfiOHOSRequestRemoveTask(int32_t taskId)
{
return CJRequestImpl::RemoveTask(taskId);
}
}
}

View File

@ -0,0 +1,254 @@
/*
* 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_request_impl.h"
#include <string>
#include "constant.h"
#include "cj_request_task.h"
#include "cj_request_common.h"
#include "cj_request_log.h"
#include "cj_request_event.h"
#include "cj_initialize.h"
namespace OHOS::CJSystemapi::Request {
using OHOS::AbilityRuntime::Context;
using OHOS::Request::ExceptionErrorCode;
using OHOS::Request::Version;
using OHOS::Request::E_OK_INFO;
using OHOS::Request::E_PERMISSION_INFO;
using OHOS::Request::E_PARAMETER_CHECK_INFO;
using OHOS::Request::E_UNSUPPORTED_INFO;
using OHOS::Request::E_FILE_IO_INFO;
using OHOS::Request::E_FILE_PATH_INFO;
using OHOS::Request::E_SERVICE_ERROR_INFO;
using OHOS::Request::E_TASK_QUEUE_INFO;
using OHOS::Request::E_TASK_MODE_INFO;
using OHOS::Request::E_TASK_NOT_FOUND_INFO;
using OHOS::Request::E_TASK_STATE_INFO;
using OHOS::Request::E_OTHER_INFO;
using OHOS::Request::FUNCTION_PAUSE;
using OHOS::Request::FUNCTION_RESUME;
using OHOS::Request::FUNCTION_START;
using OHOS::Request::FUNCTION_STOP;
static constexpr const char *NOT_SYSTEM_APP = "permission verification failed, application which is not a system "
"application uses system API";
static const std::map<ExceptionErrorCode, std::string> ErrorCodeToMsg{
{ ExceptionErrorCode::E_OK, E_OK_INFO },
{ ExceptionErrorCode::E_PERMISSION, E_PERMISSION_INFO },
{ ExceptionErrorCode::E_PARAMETER_CHECK, E_PARAMETER_CHECK_INFO },
{ ExceptionErrorCode::E_UNSUPPORTED, E_UNSUPPORTED_INFO },
{ ExceptionErrorCode::E_FILE_IO, E_FILE_IO_INFO },
{ ExceptionErrorCode::E_FILE_PATH, E_FILE_PATH_INFO },
{ ExceptionErrorCode::E_SERVICE_ERROR, E_SERVICE_ERROR_INFO },
{ ExceptionErrorCode::E_TASK_QUEUE, E_TASK_QUEUE_INFO },
{ ExceptionErrorCode::E_TASK_MODE, E_TASK_MODE_INFO },
{ ExceptionErrorCode::E_TASK_NOT_FOUND, E_TASK_NOT_FOUND_INFO },
{ ExceptionErrorCode::E_TASK_STATE, E_TASK_STATE_INFO },
{ ExceptionErrorCode::E_OTHER, E_OTHER_INFO },
{ ExceptionErrorCode::E_NOT_SYSTEM_APP, NOT_SYSTEM_APP }
};
RetError CJRequestImpl::Convert2RetErr(ExceptionErrorCode code)
{
auto iter = ErrorCodeToMsg.find(code);
std::string strMsg = (iter != ErrorCodeToMsg.end() ? iter->second : "");
return {
.errCode = code,
.errMsg = MallocCString(strMsg)
};
}
RetError CJRequestImpl::Convert2RetErr(ExceptionError &err)
{
auto iter = ErrorCodeToMsg.find(err.code);
std::string strMsg;
if (err.errInfo.empty()) {
strMsg = (iter != ErrorCodeToMsg.end() ? iter->second : "");
} else {
strMsg = (iter != ErrorCodeToMsg.end() ? iter->second + " " : "") + err.errInfo;
}
return {
.errCode = err.code,
.errMsg = MallocCString(strMsg)
};
}
std::map<std::string, std::string> CJRequestImpl::ConvertCArr2Map(const CHashStrArr *cheaders)
{
std::map<std::string, std::string> result;
for (int i = 0; i < cheaders->size; ++i) {
const CHashStrPair *cheader = &cheaders->headers[i];
result[cheader->key] = cheader->value;
}
return result;
}
void CJRequestImpl::Convert2Config(CConfig *config, Config &out)
{
out.action = (OHOS::Request::Action)config->action;
out.url = config->url;
out.version = Version::API10; //CJ only support API10
out.mode = (OHOS::Request::Mode)config->mode;
out.network = (OHOS::Request::Network)config->network;
out.index = config->index;
out.begins = config->begins;
out.ends = config->ends;
out.priority = config->priority;
out.overwrite = config->overwrite;
out.metered = config->metered;
out.roaming = config->roaming;
out.retry = config->retry;
out.redirect = config->redirect;
out.gauge = config->gauge;
out.precise = config->precise;
out.title = config->title;
out.saveas = config->saveas;
out.method = config->method;
out.token = config->token;
out.description = config->description;
out.headers = ConvertCArr2Map(&config->headers);
out.extras = ConvertCArr2Map(&config->extras);
}
RetReqData CJRequestImpl::CreateTask(OHOS::AbilityRuntime::Context* context, CConfig *FfiConfig)
{
REQUEST_HILOGD("[CJRequestImpl] CreateTask start");
Config config{};
Convert2Config(FfiConfig, config);
ExceptionError result = CJInitialize::ParseConfig(context, FfiConfig, config);
if (result.code != 0) {
return {.err = Convert2RetErr(result)};
}
RetReqData ret{};
CJTask *task = new (std::nothrow) CJTask();
if (task == nullptr) {
REQUEST_HILOGE("[CJRequestImpl] Fail to create task.");
ret.err.errCode = ExceptionErrorCode::E_OTHER;
return ret;
}
result = task->Create(context, config);
if (result.code != 0) {
REQUEST_HILOGE("[CJRequestImpl] task create failed, ret:%{public}d.", result.code);
return {.err = Convert2RetErr(result)};
}
ret.taskId = task->taskId_;
REQUEST_HILOGD("[CJRequestImpl] CreateTask end");
return ret;
}
RetError CJRequestImpl::RemoveTask(int32_t taskId)
{
RetError ret{};
CJTask *task = CJTask::FindTaskById(taskId);
if (task == nullptr) {
REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}d.", taskId);
return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
}
ExceptionError result = CJTask::Remove(task->GetTidStr());
if (result.code != ExceptionErrorCode::E_OK) {
return Convert2RetErr(result);
}
return ret;
}
void CJRequestImpl::FreeTask(int32_t taskId)
{
REQUEST_HILOGD("[CJRequestImpl] FreeTask start");
delete CJTask::ClearTaskMap(std::to_string(taskId));
}
RetError CJRequestImpl::ProgressOn(char *event, int32_t taskId, void (*callback)(CProgress progress))
{
REQUEST_HILOGD("[CJRequestImpl] ProgressOn start");
RetError ret{};
CJTask *task = CJTask::FindTaskById(taskId);
if (task == nullptr) {
REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}d.", taskId);
return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
}
ExceptionError result = task->On(event, taskId, callback);
if (result.code != 0) {
REQUEST_HILOGE("[CJRequestImpl] task on failed, ret:%{public}d.", result.code);
return Convert2RetErr(result);
}
return ret;
}
RetError CJRequestImpl::ProgressOff(char *event, int32_t taskId, void *callback)
{
REQUEST_HILOGD("[CJRequestImpl] ProgressOff start");
RetError ret{};
CJTask *task = CJTask::FindTaskById(taskId);
if (task == nullptr) {
REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}d.", taskId);
return ret;
}
ExceptionError result = task->Off(event, callback);
if (result.code != 0) {
REQUEST_HILOGE("[CJRequestImpl] task off failed, ret:%{public}d.", result.code);
return Convert2RetErr(result);
}
return ret;
}
RetError CJRequestImpl::TaskExec(std::string execType, int32_t taskId)
{
REQUEST_HILOGD("[CJRequestImpl] TaskExec start");
RetError ret{};
CJTask *task = CJTask::FindTaskById(taskId);
if (task == nullptr) {
REQUEST_HILOGE("[CJRequestImpl] Fail to find task, id:%{public}d.", taskId);
return Convert2RetErr(ExceptionErrorCode::E_TASK_NOT_FOUND);
}
ExceptionErrorCode code = CJRequestEvent::Exec(execType, task);
if (code != ExceptionErrorCode::E_OK) {
return Convert2RetErr(code);
}
return ret;
}
RetError CJRequestImpl::TaskStart(int32_t taskId)
{
return CJRequestImpl::TaskExec(FUNCTION_START, taskId);
}
RetError CJRequestImpl::TaskPause(int32_t taskId)
{
return CJRequestImpl::TaskExec(FUNCTION_PAUSE, taskId);
}
RetError CJRequestImpl::TaskResume(int32_t taskId)
{
return CJRequestImpl::TaskExec(FUNCTION_RESUME, taskId);
}
RetError CJRequestImpl::TaskStop(int32_t taskId)
{
return CJRequestImpl::TaskExec(FUNCTION_STOP, taskId);
}
} //namespace OHOS::CJSystemapi::Request

View File

@ -0,0 +1,28 @@
/*
* 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_ffi/cj_common_ffi.h"
extern "C" {
FFI_EXPORT int FfiOHOSRequestCreateTask = 0;
FFI_EXPORT int FfiOHOSRequestFreeTask = 0;
FFI_EXPORT int FfiOHOSRequestTaskProgressOn = 0;
FFI_EXPORT int FfiOHOSRequestTaskProgressOff = 0;
FFI_EXPORT int FfiOHOSRequestTaskStart = 0;
FFI_EXPORT int FfiOHOSRequestTaskPause = 0;
FFI_EXPORT int FfiOHOSRequestTaskResume = 0;
FFI_EXPORT int FfiOHOSRequestTaskStop = 0;
FFI_EXPORT int FfiOHOSRequestRemoveTask = 0;
}

View File

@ -0,0 +1,394 @@
/*
* 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_request_task.h"
#include <cstring>
#include <fcntl.h>
#include <filesystem>
#include <fstream>
#include <regex>
#include <sys/stat.h>
#include "securec.h"
#include "application_context.h"
#include "storage_acl.h"
#include "constant.h"
#include "request_manager.h"
#include "cj_app_state_callback.h"
#include "cj_initialize.h"
#include "cj_lambda.h"
#include "cj_request_common.h"
#include "cj_request_event.h"
#include "cj_request_log.h"
namespace OHOS::CJSystemapi::Request {
namespace fs = std::filesystem;
using OHOS::AbilityRuntime::Context;
using OHOS::Request::Version;
using OHOS::Request::ExceptionErrorCode;
using OHOS::Request::Action;
using OHOS::Request::RequestManager;
using OHOS::StorageDaemon::AclSetAccess;
std::mutex CJTask::taskMutex_;
std::map<std::string, CJTask*> CJTask::taskMap_;
std::mutex CJTask::pathMutex_;
std::map<std::string, int32_t> CJTask::pathMap_;
bool CJTask::register_ = false;
static constexpr int ACL_SUCC = 0;
static const std::string SA_PERMISSION_RWX = "g:3815:rwx";
static const std::string SA_PERMISSION_X = "g:3815:x";
static const std::string SA_PERMISSION_CLEAN = "g:3815:---";
CJTask::CJTask()
{
config_.version = Version::API10;
config_.action = Action::ANY;
REQUEST_HILOGI("construct CJTask()");
}
CJTask::~CJTask()
{
REQUEST_HILOGI("~CJTask()");
RequestManager::GetInstance()->RemoveAllListeners(GetTidStr());
}
std::string CJTask::GetTidStr() const
{
return tid_;
}
void CJTask::SetTid()
{
tid_ = std::to_string(taskId_);
}
void CJTask::AddTaskMap(const std::string &key, CJTask *task)
{
std::lock_guard<std::mutex> lockGuard(CJTask::taskMutex_);
CJTask::taskMap_[key] = task;
}
CJTask* CJTask::FindTaskById(int32_t taskId)
{
CJTask *task = nullptr;
{
std::lock_guard<std::mutex> lockGuard(CJTask::taskMutex_);
auto item = CJTask::taskMap_.find(std::to_string(taskId));
if (item == CJTask::taskMap_.end()) {
return nullptr;
}
task = item->second;
}
return task;
}
CJTask* CJTask::ClearTaskMap(const std::string &key)
{
std::lock_guard<std::mutex> lockGuard(CJTask::taskMutex_);
auto it = taskMap_.find(key);
if (it == taskMap_.end()) {
return nullptr;
}
taskMap_.erase(it);
return it->second;
}
bool CJTask::SetPathPermission(const std::string &filepath)
{
std::string baseDir;
if (!CJInitialize::GetBaseDir(baseDir) || filepath.find(baseDir) == std::string::npos) {
REQUEST_HILOGE("File dir not found.");
return false;
}
AddPathMap(filepath, baseDir);
for (auto it : pathMap_) {
if (it.second <= 0) {
continue;
}
if (AclSetAccess(it.first, SA_PERMISSION_X) != ACL_SUCC) {
REQUEST_HILOGE("AclSetAccess Parent Dir Failed.");
return false;
}
}
std::string childDir = filepath.substr(0, filepath.rfind("/"));
if (AclSetAccess(childDir, SA_PERMISSION_RWX) != ACL_SUCC) {
REQUEST_HILOGE("AclSetAccess Child Dir Failed.");
return false;
}
return true;
}
bool CJTask::SetDirsPermission(std::vector<std::string> &dirs)
{
if (dirs.empty()) {
return true;
}
std::string newPath = "/data/storage/el2/base/.ohos/.request/.certs";
std::vector<std::string> dirElems;
CJInitialize::StringSplit(newPath, '/', dirElems);
if (!CJInitialize::CreateDirs(dirElems)) {
REQUEST_HILOGE("CreateDirs Err: %{public}s", newPath.c_str());
return false;
}
for (const auto &folderPath : dirs) {
fs::path folder = folderPath;
if (!(fs::exists(folder) && fs::is_directory(folder))) {
return false;
}
for (const auto &entry : fs::directory_iterator(folder)) {
fs::path path = entry.path();
std::string existfilePath = folder.string() + "/" + path.filename().string();
std::string newfilePath = newPath + "/" + path.filename().string();
if (!fs::exists(newfilePath)) {
fs::copy(existfilePath, newfilePath);
}
if (chmod(newfilePath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
REQUEST_HILOGD("File add OTH access Failed.");
}
REQUEST_HILOGD("current filePath is %{public}s", newfilePath.c_str());
if (!CJTask::SetPathPermission(newfilePath)) {
REQUEST_HILOGE("Set path permission fail.");
return false;
}
}
}
if (!dirs.empty()) {
dirs.clear();
dirs.push_back(newPath);
}
return true;
}
void CJTask::AddPathMap(const std::string &filepath, const std::string &baseDir)
{
std::string childDir(filepath);
std::string parentDir;
while (childDir.length() > baseDir.length()) {
parentDir = childDir.substr(0, childDir.rfind("/"));
std::lock_guard<std::mutex> lockGuard(CJTask::pathMutex_);
auto it = pathMap_.find(parentDir);
if (it == pathMap_.end()) {
pathMap_[parentDir] = 1;
} else {
pathMap_[parentDir] += 1;
}
childDir = parentDir;
}
}
void CJTask::ResetDirAccess(const std::string &filepath)
{
int ret = AclSetAccess(filepath, SA_PERMISSION_CLEAN);
if (ret != ACL_SUCC) {
REQUEST_HILOGE("AclSetAccess Reset Dir Failed: %{public}s", filepath.c_str());
}
}
void CJTask::RemovePathMap(const std::string &filepath)
{
std::string baseDir;
if (!CJInitialize::GetBaseDir(baseDir) || filepath.find(baseDir) == std::string::npos) {
REQUEST_HILOGE("File dir not found.");
return;
}
if (chmod(filepath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
REQUEST_HILOGE("File remove WOTH access Failed.");
}
std::string childDir(filepath);
std::string parentDir;
while (childDir.length() > baseDir.length()) {
parentDir = childDir.substr(0, childDir.rfind("/"));
std::lock_guard<std::mutex> lockGuard(CJTask::pathMutex_);
auto it = pathMap_.find(parentDir);
if (it != pathMap_.end()) {
if (pathMap_[parentDir] <= 1) {
pathMap_.erase(parentDir);
ResetDirAccess(parentDir);
} else {
pathMap_[parentDir] -= 1;
}
}
childDir = parentDir;
}
}
void CJTask::RemoveDirsPermission(const std::vector<std::string> &dirs)
{
for (const auto &folderPath : dirs) {
fs::path folder = folderPath;
for (const auto &entry : fs::directory_iterator(folder)) {
fs::path path = entry.path();
std::string filePath = folder.string() + "/" + path.filename().string();
RemovePathMap(filePath);
}
}
}
void CJTask::RegisterForegroundResume()
{
if (register_) {
return;
}
register_ = true;
auto context = AbilityRuntime::ApplicationContext::GetInstance();
if (context == nullptr) {
REQUEST_HILOGE("Get ApplicationContext failed");
return;
}
context->RegisterAbilityLifecycleCallback(std::make_shared<CJAppStateCallback>());
REQUEST_HILOGD("Register foreground resume callback success");
}
ExceptionError CJTask::Create(Context* context, Config &config)
{
int32_t seq = RequestManager::GetInstance()->GetNextSeq();
REQUEST_HILOGI("Begin task create, seq: %{public}d", seq);
config_ = config;
RequestManager::GetInstance()->RestoreListener(CJTask::ReloadListener);
if (!RequestManager::GetInstance()->LoadRequestServer()) {
return {.code = ExceptionErrorCode::E_SERVICE_ERROR};
}
if (config.mode == Mode::FOREGROUND) {
RegisterForegroundResume();
}
int32_t err = RequestManager::GetInstance()->Create(config_, seq, taskId_);
if (err != ExceptionErrorCode::E_OK) {
REQUEST_HILOGE("Create task failed, in");
return {.code = (ExceptionErrorCode)err};
}
SetTid();
listenerMutex_.lock();
notifyDataListenerMap_[SubscribeType::REMOVE] =
std::make_shared<CJNotifyDataListener>(GetTidStr(), SubscribeType::REMOVE);
listenerMutex_.unlock();
RequestManager::GetInstance()->AddListener(
GetTidStr(), SubscribeType::REMOVE, notifyDataListenerMap_[SubscribeType::REMOVE]);
AddTaskMap(GetTidStr(), this);
return {.code = ExceptionErrorCode::E_OK};
}
ExceptionError CJTask::Remove(const std::string &tid)
{
int result = RequestManager::GetInstance()->Remove(tid, Version::API10);
if (result != ExceptionErrorCode::E_OK) {
return ConvertError(result);
}
return {
.code = ExceptionErrorCode::E_OK
};
}
void CJTask::ReloadListener()
{
REQUEST_HILOGD("ReloadListener in");
std::lock_guard<std::mutex> lockGuard(CJTask::taskMutex_);
RequestManager::GetInstance()->ReopenChannel();
for (const auto &it : taskMap_) {
RequestManager::GetInstance()->Subscribe(it.first);
}
}
ExceptionError CJTask::On(std::string type, int32_t taskId, void (*callback)(CProgress progress))
{
int32_t seq = RequestManager::GetInstance()->GetNextSeq();
REQUEST_HILOGI("Begin task on, seq: %{public}d", seq);
SubscribeType subscribeType = CJRequestEvent::StringToSubscribeType(type);
if (subscribeType == SubscribeType::BUTT) {
return { .code = ExceptionErrorCode::E_PARAMETER_CHECK, .errInfo = "First parameter error" };
}
listenerMutex_.lock();
auto listener = notifyDataListenerMap_.find(subscribeType);
if (listener == notifyDataListenerMap_.end()) {
notifyDataListenerMap_[subscribeType] =
std::make_shared<CJNotifyDataListener>(GetTidStr(), subscribeType);
}
listenerMutex_.unlock();
notifyDataListenerMap_[subscribeType]->AddListener(CJLambda::Create(callback),
(CFunc)callback);
REQUEST_HILOGI("End task on event %{public}s successfully, seq: %{public}d, tid: %{public}s", type.c_str(), seq,
GetTidStr().c_str());
return {.code = ExceptionErrorCode::E_OK};
}
ExceptionError CJTask::Off(std::string event, CFunc callback)
{
int32_t seq = RequestManager::GetInstance()->GetNextSeq();
REQUEST_HILOGI("Begin task off, seq: %{public}d", seq);
SubscribeType subscribeType = CJRequestEvent::StringToSubscribeType(event);
if (subscribeType == SubscribeType::BUTT) {
return { .code = ExceptionErrorCode::E_PARAMETER_CHECK, .errInfo = "First parameter error" };
}
listenerMutex_.lock();
auto listener = notifyDataListenerMap_.find(subscribeType);
if (listener == notifyDataListenerMap_.end()) {
notifyDataListenerMap_[subscribeType] =
std::make_shared<CJNotifyDataListener>(GetTidStr(), subscribeType);
}
listenerMutex_.unlock();
notifyDataListenerMap_[subscribeType]->RemoveListener((CFunc)callback);
return {.code = ExceptionErrorCode::E_OK};
}
void CJTask::ClearTaskTemp(const std::string &tid, bool isRmFiles, bool isRmAcls, bool isRmCertsAcls)
{
std::lock_guard<std::mutex> lockGuard(CJTask::taskMutex_);
auto item = CJTask::taskMap_.find(tid);
if (item == CJTask::taskMap_.end()) {
REQUEST_HILOGD("Clear task tmp files, not find task");
return;
}
auto task = item->second;
if (isRmFiles) {
auto bodyFileNames = task->config_.bodyFileNames;
for (auto &filePath : bodyFileNames) {
RemovePathMap(filePath);
RemoveFile(filePath);
}
}
if (isRmAcls) {
// Reset Acl permission
for (auto &file : task->config_.files) {
RemovePathMap(file.uri);
}
}
if (isRmCertsAcls) {
RemoveDirsPermission(task->config_.certsPath);
}
}
} //namespace OHOS::CJSystemapi::Request

View File

@ -0,0 +1,22 @@
/*
* 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_response_listener.h"
#include "request_manager.h"
namespace OHOS::CJSystemapi::Request {
} // namespace OHOS::CJSystemapi::Request