• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <ani.h>
16 #include <fcntl.h>
17 #include <securec.h>
18 #include <sys/stat.h>
19 #include <filesystem>
20 #include <iostream>
21 #include <regex>
22 #include <string>
23 #include <system_error>
24 
25 #include "constant.h"
26 #include "class.h"
27 #include "log.h"
28 #include "memory.h"
29 #include "ani_utils.h"
30 #include "ani_task.h"
31 #include "ani_js_initialize.h"
32 #include "request_common.h"
33 
34 using namespace OHOS;
35 using namespace OHOS::Request;
36 using namespace OHOS::AniUtil;
37 
38 template<>
TryConvertArray(std::vector<ani_ref> & value)39 bool UnionAccessor::TryConvertArray<ani_ref>(std::vector<ani_ref> &value)
40 {
41     ani_double length;
42     if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) {
43         return false;
44     }
45 
46     for (int i = 0; i < int(length); i++) {
47         ani_ref ref;
48         if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) {
49             return false;
50         }
51         value.push_back(ref);
52     }
53     return true;
54 }
55 
ThrowBusinessError(ani_env * env,int errCode,std::string && errMsg)56 static void ThrowBusinessError(ani_env *env, int errCode, std::string&& errMsg)
57 {
58     REQUEST_HILOGI("into ThrowBusinessError.");
59     static const char *errorClsName = "L@ohos/base/BusinessError;";
60     ani_class cls {};
61     if (env->FindClass(errorClsName, &cls) != ANI_OK) {
62         REQUEST_HILOGE("find class BusinessError %{public}s failed", errorClsName);
63         return;
64     }
65     ani_method ctor;
66     if (env->Class_FindMethod(cls, "<ctor>", ":V", &ctor) != ANI_OK) {
67         REQUEST_HILOGE("find method BusinessError.constructor failed");
68         return;
69     }
70     ani_object errorObject;
71     if (env->Object_New(cls, ctor, &errorObject) != ANI_OK) {
72         REQUEST_HILOGE("create BusinessError object failed");
73         return;
74     }
75     ani_double aniErrCode = static_cast<ani_double>(errCode);
76     ani_string errMsgStr;
77     if (env->String_NewUTF8(errMsg.c_str(), errMsg.size(), &errMsgStr) != ANI_OK) {
78         REQUEST_HILOGE("convert errMsg to ani_string failed");
79         return;
80     }
81     if (env->Object_SetFieldByName_Double(errorObject, "code", aniErrCode) != ANI_OK) {
82         REQUEST_HILOGE("set error code failed");
83         return;
84     }
85     if (env->Object_SetPropertyByName_Ref(errorObject, "message", errMsgStr) != ANI_OK) {
86         REQUEST_HILOGE("set error message failed");
87         return;
88     }
89     env->ThrowError(static_cast<ani_error>(errorObject));
90     return;
91 }
92 
InitConfig(ani_env * env,ani_object object,Config & config)93 static ExceptionError InitConfig(ani_env *env, ani_object object, Config &config)
94 {
95     std::shared_ptr<OHOS::AbilityRuntime::Context> context = nullptr;
96     ExceptionError error = { .code = E_OK };
97     context = JsInitialize::GetContext(env, object);
98     if (context == nullptr) {
99         REQUEST_HILOGE("context == null");
100         error.code = E_PARAMETER_CHECK;
101         error.errInfo = "Parameter verification failed, Get context fail";
102         return error;
103     }
104     auto applicationInfo = context->GetApplicationInfo();
105     if (applicationInfo == nullptr) {
106         REQUEST_HILOGE("ApplicationInfo == null");
107         error.code = E_OTHER;
108         error.errInfo = "ApplicationInfo is null";
109         return error;
110     }
111     config.bundleType = static_cast<u_int32_t>(applicationInfo->bundleType);
112     config.bundleName = context->GetBundleName();
113     config.version = Version::API10;
114     bool ret = JsInitialize::CheckFilePath(context, config, error);
115     if (!ret) {
116         REQUEST_HILOGE("error info is: %{public}s", error.errInfo.c_str());
117     }
118     return error;
119 }
120 
IsArray(ani_env * env,ani_object aniData)121 static bool IsArray(ani_env *env, ani_object aniData)
122 {
123     ani_double length;
124     if (ANI_OK != env->Object_GetPropertyByName_Double(aniData, "length", &length)) {
125         return false;
126     }
127     return true;
128 }
129 
IsInstanceOf(ani_env * env,const std::string & cls_name,ani_object obj)130 ani_boolean OHOS::AniUtil::IsInstanceOf(ani_env *env, const std::string &cls_name, ani_object obj)
131 {
132     ani_class cls;
133     if (ANI_OK != env->FindClass(cls_name.c_str(), &cls)) {
134         return ANI_FALSE;
135     }
136 
137     ani_boolean ret;
138     env->Object_InstanceOf(obj, cls, &ret);
139     return ret;
140 }
141 
GetDownloadData(ani_env * env,Config & aniConfig,ani_object aniData)142 static bool GetDownloadData(ani_env *env, Config &aniConfig, ani_object aniData)
143 {
144     UnionAccessor unionAccessor(env, aniData);
145     if (unionAccessor.IsInstanceOf("Lstd/core/String;")) {
146         aniConfig.data = AniStringUtils::ToStd(env, static_cast<ani_string>(aniData));
147     }
148     return true;
149 }
150 
ProcessDatas(ani_env * env,Config & aniConfig,ani_object aniData)151 static bool ProcessDatas(ani_env *env, Config &aniConfig, ani_object aniData)
152 {
153     UnionAccessor unionAccessor(env, aniData);
154     if (aniConfig.action == Action::DOWNLOAD) {
155         return GetDownloadData(env, aniConfig, aniData);
156     }
157     if (aniConfig.action != Action::UPLOAD) {
158         return false;
159     }
160 
161     std::vector<ani_ref> arrayDoubleValues = {};
162     if (!unionAccessor.TryConvertArray<ani_ref>(arrayDoubleValues) || arrayDoubleValues.empty()) {
163         return false;
164     }
165 
166     for (uint16_t i = 0; i < arrayDoubleValues.size(); i++) {
167         ani_object data = static_cast<ani_object>(arrayDoubleValues[i]);
168         ani_ref nameRef;
169         if (ANI_OK != env->Object_GetPropertyByName_Ref(data, "name", &nameRef)) {
170             REQUEST_HILOGE("Object_GetFieldByName_Ref name from data Faild");
171             return false;
172         }
173         auto name = AniStringUtils::ToStd(env, static_cast<ani_string>(nameRef));
174 
175         ani_ref valueRef;
176         if (ANI_OK != env->Object_GetPropertyByName_Ref(data, "value", &valueRef)) {
177             REQUEST_HILOGE("Object_GetFieldByName_Ref value from data Faild");
178             return false;
179         }
180         if (IsInstanceOf(env, "Lstd/core/String;", static_cast<ani_object>(valueRef))) {
181             FormItem form;
182             form.name = name;
183             form.value = AniStringUtils::ToStd(env, static_cast<ani_string>(valueRef));
184             aniConfig.forms.push_back(form);
185             continue;
186         }
187         if (IsInstanceOf(env, "L@ohos/request/request/agent/FileSpec;", static_cast<ani_object>(valueRef))) {
188             FileSpec file;
189             if (!JsInitialize::Convert2FileSpec(env, static_cast<ani_object>(valueRef), name, file)) {
190                 REQUEST_HILOGE("Convert2FileSpec failed");
191                 return false;
192             }
193             aniConfig.files.push_back(file);
194             continue;
195         }
196         if (!IsArray(env, static_cast<ani_object>(valueRef))) {
197             return false;
198         }
199         if (!JsInitialize::Convert2FileSpecs(env, static_cast<ani_object>(valueRef), name, aniConfig.files)) {
200             return false;
201         }
202     }
203     return true;
204 }
205 
SetConfigInfo(ani_env * env,Config & aniConfig,ani_object config)206 static bool SetConfigInfo(ani_env *env, Config &aniConfig, ani_object config)
207 {
208     ani_ref url;
209     if (ANI_OK != env->Object_GetPropertyByName_Ref(config, "url", &url)) {
210         REQUEST_HILOGI("Failed to get property named type");
211         return false;
212     }
213     auto urlStr = AniStringUtils::ToStd(env, static_cast<ani_string>(url));
214     REQUEST_HILOGI("urlStr: %{public}s", urlStr.c_str());
215     aniConfig.url = urlStr;
216     ani_ref aniAction;
217     if (ANI_OK != env->Object_GetPropertyByName_Ref(config, "action", &aniAction)) {
218         REQUEST_HILOGI("Failed to get property named type");
219         return false;
220     }
221     EnumAccessor actionAccessor(env, static_cast<ani_enum_item>(aniAction));
222     expected<Action, ani_status> actionExpected = actionAccessor.To<Action>();
223     if (!actionExpected) {
224         return false;
225     }
226     Action action = actionExpected.value();
227     aniConfig.action = action;
228     REQUEST_HILOGI("vibrateInfo.type: %{public}d", action);
229 
230     aniConfig.overwrite = true;
231 
232     ani_ref aniMethod;
233     if (env->Object_GetPropertyByName_Ref(config, "method", &aniMethod) == ANI_OK && aniMethod != nullptr) {
234         auto method = AniStringUtils::ToStd(env, static_cast<ani_string>(aniMethod));
235         aniConfig.method = method;
236     }
237 
238     ani_ref aniSaveas;
239     if (env->Object_GetPropertyByName_Ref(config, "saveas", &aniSaveas) == ANI_OK && aniSaveas != nullptr) {
240         auto saveas = AniStringUtils::ToStd(env, static_cast<ani_string>(aniSaveas));
241         aniConfig.saveas = saveas;
242     }
243 
244     ani_ref aniData;
245     if (env->Object_GetPropertyByName_Ref(config, "data", &aniData) == ANI_OK && aniData != nullptr) {
246         bool ret = ProcessDatas(env, aniConfig, static_cast<ani_object>(aniData));
247         if (!ret) {
248             REQUEST_HILOGE("ProcessDatas data error.");
249             return ret;
250         }
251     }
252     return true;
253 }
254 
Create(ani_env * env,ani_object object,ani_object config)255 static ani_object Create([[maybe_unused]] ani_env *env, ani_object object, ani_object config)
256 {
257     REQUEST_HILOGI("Create Start");
258     ani_object nullobj{};
259     if (object == nullptr) {
260         REQUEST_HILOGE("context == null");
261         return nullobj;
262     }
263     if (config == nullptr) {
264         REQUEST_HILOGE("config == null");
265         return nullobj;
266     }
267 
268     Config aniConfig{};
269     aniConfig.saveas = "default.txt";
270     if (!SetConfigInfo(env, aniConfig, config)) {
271         REQUEST_HILOGE("Failed to SetConfigInfo.");
272         return nullobj;
273     }
274 
275     ExceptionError err = InitConfig(env, object, aniConfig);
276     if (err.code != E_OK) {
277         REQUEST_HILOGE("err.code : %{public}d, err.errInfo :  %{public}s", err.code, err.errInfo.c_str());
278         ThrowBusinessError(env, err.code, std::move(err.errInfo));
279         return nullobj;
280     }
281 
282     AniTask *task = AniTask::Create(env, aniConfig);
283     if (task == nullptr) {
284         REQUEST_HILOGE("AniTask::Create task == nullptr!");
285         return nullobj;
286     }
287 
288     auto taskImpl = AniObjectUtils::Create(env, "L@ohos/request/request;", "Lagent;", "LTaskImpl;");
289 
290     NativePtrWrapper wrapper(env, taskImpl);
291     wrapper.Wrap<AniTask>(task);
292     return taskImpl;
293 }
294 
StartSync(ani_env * env,ani_object object)295 static void StartSync([[maybe_unused]] ani_env *env, ani_object object)
296 {
297     REQUEST_HILOGI("Enter Start");
298     if (env == nullptr) {
299         return;
300     }
301     NativePtrWrapper wrapper(env, object);
302     auto task = wrapper.Unwrap<AniTask>();
303     if (task == nullptr) {
304         REQUEST_HILOGE("task is nullptr");
305         return;
306     }
307     task->Start(env);
308 }
309 
OnSync(ani_env * env,ani_object object,ani_string response,ani_object callback)310 static void OnSync([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object,
311     ani_string response, ani_object callback)
312 {
313     REQUEST_HILOGI("Enter On");
314 
315     ani_ref callbackRef = nullptr;
316     env->GlobalReference_Create(reinterpret_cast<ani_ref>(callback), &callbackRef);
317     auto responseEvent = AniStringUtils::ToStd(env, static_cast<ani_string>(response));
318     NativePtrWrapper wrapper(env, object);
319     auto task = wrapper.Unwrap<AniTask>();
320     if (task == nullptr) {
321         REQUEST_HILOGE("task is nullptr");
322         return;
323     }
324     task->On(env, responseEvent, callbackRef);
325 }
326 
ANI_Constructor(ani_vm * vm,uint32_t * result)327 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
328 {
329     REQUEST_HILOGI("Enter ANI_Constructor Start");
330     ani_env *env;
331     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
332         REQUEST_HILOGI("Unsupported ANI_VERSION_1");
333         return ANI_ERROR;
334     }
335 
336     static const char *namespaceName = "L@ohos/request/request;";
337     ani_namespace request;
338     if (ANI_OK != env->FindNamespace(namespaceName, &request)) {
339         REQUEST_HILOGI("Not found '%{public}s'", namespaceName);
340         return ANI_ERROR;
341     }
342 
343     static const char *agentNamespaceName = "Lagent;";
344     ani_namespace agent;
345     if (ANI_OK != env->Namespace_FindNamespace(request, agentNamespaceName, &agent)) {
346         REQUEST_HILOGI("Not found '%{public}s'", agentNamespaceName);
347         return ANI_ERROR;
348     }
349     std::array nsMethods = {
350         ani_native_function {"createSync", nullptr, reinterpret_cast<void *>(Create)},
351     };
352 
353     if (ANI_OK != env->Namespace_BindNativeFunctions(agent, nsMethods.data(), nsMethods.size())) {
354         REQUEST_HILOGI("Cannot bind native methods to '%{public}s'", namespaceName);
355         return ANI_ERROR;
356     };
357 
358     static const char *requestclsName = "LTaskImpl;";
359     ani_class requestClass;
360     if (ANI_OK != env->Namespace_FindClass(agent, requestclsName, &requestClass)) {
361         REQUEST_HILOGI("Not found class %{public}s", requestclsName);
362         return ANI_NOT_FOUND;
363     }
364 
365     std::array methods = {
366         ani_native_function {"startSync", nullptr, reinterpret_cast<void *>(StartSync)},
367         ani_native_function {"onSync", nullptr, reinterpret_cast<void *>(OnSync)},
368     };
369 
370     if (ANI_OK != env->Class_BindNativeMethods(requestClass, methods.data(), methods.size())) {
371         REQUEST_HILOGI("Cannot bind native methods to %{public}s", requestclsName);
372         return ANI_ERROR;
373     }
374 
375     auto cleanerCls = TypeFinder(env).FindClass(agent, "LCleaner;");
376     NativePtrCleaner(env).Bind(cleanerCls.value());
377 
378     *result = ANI_VERSION_1;
379     return ANI_OK;
380 }
381