1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "napi_utils.h"
17
18 #include <fcntl.h>
19
20 #include <cstdint>
21 #include <cstring>
22 #include <fstream>
23 #include <initializer_list>
24 #include <memory>
25 #include <regex>
26
27 #include "log.h"
28 #include "request_manager.h"
29 #include "securec.h"
30
31 namespace OHOS::Request::NapiUtils {
32 static constexpr int64_t JS_NUMBER_MAX_VALUE = (1LL << 53) - 1;
33 static constexpr const char *REASON_OK_INFO = "Task successful";
34 static constexpr const char *TASK_SURVIVAL_ONE_MONTH_INFO = "The task has not been completed for a month yet";
35 static constexpr const char *WAITTING_NETWORK_ONE_DAY_INFO = "The task waiting for network recovery has not been "
36 "completed for a day yet";
37 static constexpr const char *STOPPED_NEW_FRONT_TASK_INFO = "Stopped by a new front task";
38 static constexpr const char *RUNNING_TASK_MEET_LIMITS_INFO = "Too many task in running state";
39 static constexpr const char *USER_OPERATION_INFO = "User operation";
40 static constexpr const char *APP_BACKGROUND_OR_TERMINATE_INFO = "The app is background or terminate";
41 static constexpr const char *NETWORK_OFFLINE_INFO = "NetWork is offline";
42 static constexpr const char *UNSUPPORTED_NETWORK_TYPE_INFO = "NetWork type not meet the task config";
43 static constexpr const char *BUILD_CLIENT_FAILED_INFO = "Build client error";
44 static constexpr const char *BUILD_REQUEST_FAILED_INFO = "Build request error";
45 static constexpr const char *GET_FILESIZE_FAILED_INFO = "Failed because cannot get the file size from the server and "
46 "the precise is setted true by user";
47 static constexpr const char *CONTINUOUS_TASK_TIMEOUT_INFO = "Continuous processing task time out";
48 static constexpr const char *CONNECT_ERROR_INFO = "Connect error";
49 static constexpr const char *REQUEST_ERROR_INFO = "Request error";
50 static constexpr const char *UPLOAD_FILE_ERROR_INFO = "There are some files upload failed";
51 static constexpr const char *REDIRECT_ERROR_INFO = "Redirect error";
52 static constexpr const char *PROTOCOL_ERROR_INFO = "Http protocol error";
53 static constexpr const char *IO_ERROR_INFO = "Io Error";
54 static constexpr const char *UNSUPPORT_RANGE_REQUEST_INFO = "Range request not supported";
55 static constexpr const char *OTHERS_ERROR_INFO = "Some other error occured";
56 static constexpr const char *ACCOUNT_STOPPED_INFO = "Account stopped";
57 static constexpr const char *NETWORK_CHANGED_INFO = "Network changed";
58 static constexpr const char *DNS_INFO = "DNS error";
59 static constexpr const char *TCP_INFO = "TCP error";
60 static constexpr const char *SSL_INFO = "TSL/SSL error";
61 static constexpr const char *INSUFFICIENT_SPACE_INFO = "Insufficient space error";
62 static constexpr const char *NETWORK_APP_INFO = "NetWork is offline and the app is background or terminate";
63 static constexpr const char *NETWORK_ACCOUNT_INFO = "NetWork is offline and the account is stopped";
64 static constexpr const char *APP_ACCOUNT_INFO = "The account is stopped and the app is background or terminate";
65 static constexpr const char *NETWORK_ACCOUNT_APP_INFO = "NetWork is offline and the account is stopped and the app is "
66 "background or terminate";
67 static constexpr const char *NOT_SYSTEM_APP = "permission verification failed, application which is not a system "
68 "application uses system API";
69
70 static const std::map<ExceptionErrorCode, std::string> ErrorCodeToMsg{ { E_OK, E_OK_INFO },
71 { E_PERMISSION, E_PERMISSION_INFO }, { E_PARAMETER_CHECK, E_PARAMETER_CHECK_INFO },
72 { E_UNSUPPORTED, E_UNSUPPORTED_INFO }, { E_FILE_IO, E_FILE_IO_INFO }, { E_FILE_PATH, E_FILE_PATH_INFO },
73 { E_SERVICE_ERROR, E_SERVICE_ERROR_INFO }, { E_TASK_QUEUE, E_TASK_QUEUE_INFO }, { E_TASK_MODE, E_TASK_MODE_INFO },
74 { E_TASK_NOT_FOUND, E_TASK_NOT_FOUND_INFO }, { E_TASK_STATE, E_TASK_STATE_INFO }, { E_OTHER, E_OTHER_INFO },
75 { E_NOT_SYSTEM_APP, NOT_SYSTEM_APP } };
76
Convert2JSValue(napi_env env,const DownloadInfo & in,napi_value & out)77 napi_status Convert2JSValue(napi_env env, const DownloadInfo &in, napi_value &out)
78 {
79 napi_create_object(env, &out);
80 SetStringPropertyUtf8(env, out, "description", in.description);
81 SetUint32Property(env, out, "downloadedBytes", in.downloadedBytes);
82 SetUint32Property(env, out, "downloadId", in.downloadId);
83 SetUint32Property(env, out, "failedReason", in.failedReason);
84 SetStringPropertyUtf8(env, out, "fileName", in.fileName);
85 SetStringPropertyUtf8(env, out, "filePath", in.filePath);
86 SetUint32Property(env, out, "pausedReason", in.pausedReason);
87 SetUint32Property(env, out, "status", in.status);
88 SetStringPropertyUtf8(env, out, "targetURI", in.url);
89 SetStringPropertyUtf8(env, out, "downloadTitle", in.downloadTitle);
90 SetInt64Property(env, out, "downloadTotalBytes", in.downloadTotalBytes);
91 return napi_ok;
92 }
93
Convert2JSValue(napi_env env,std::string & in,napi_value & out)94 napi_status Convert2JSValue(napi_env env, std::string &in, napi_value &out)
95 {
96 return napi_create_string_utf8(env, in.c_str(), strlen(in.c_str()), &out);
97 }
98
Convert2JSValue(napi_env env,bool in,napi_value & out)99 napi_status Convert2JSValue(napi_env env, bool in, napi_value &out)
100 {
101 return napi_get_boolean(env, in, &out);
102 }
103
Convert2JSValue(napi_env env,bool code)104 napi_value Convert2JSValue(napi_env env, bool code)
105 {
106 napi_value value = nullptr;
107 if (napi_get_boolean(env, code, &value) != napi_ok) {
108 return nullptr;
109 }
110 return value;
111 }
112
Convert2JSValue(napi_env env,int32_t code)113 napi_value Convert2JSValue(napi_env env, int32_t code)
114 {
115 napi_value value = nullptr;
116 if (napi_create_int32(env, code, &value) != napi_ok) {
117 return nullptr;
118 }
119 return value;
120 }
121
Convert2JSValue(napi_env env,uint32_t code)122 napi_value Convert2JSValue(napi_env env, uint32_t code)
123 {
124 napi_value value = nullptr;
125 if (napi_create_uint32(env, code, &value) != napi_ok) {
126 return nullptr;
127 }
128 return value;
129 }
130
Convert2JSValue(napi_env env,int64_t code)131 napi_value Convert2JSValue(napi_env env, int64_t code)
132 {
133 napi_value value = nullptr;
134 if (napi_create_int64(env, code, &value) != napi_ok) {
135 return nullptr;
136 }
137 return value;
138 }
139
Convert2JSValue(napi_env env,uint64_t code)140 napi_value Convert2JSValue(napi_env env, uint64_t code)
141 {
142 if (code > JS_NUMBER_MAX_VALUE) {
143 return nullptr;
144 }
145 napi_value value = nullptr;
146 if (napi_create_int64(env, static_cast<int64_t>(code), &value) != napi_ok) {
147 return nullptr;
148 }
149 return value;
150 }
151
Convert2JSValue(napi_env env,const std::vector<int64_t> & code)152 napi_value Convert2JSValue(napi_env env, const std::vector<int64_t> &code)
153 {
154 napi_value value = nullptr;
155 napi_create_array_with_length(env, code.size(), &value);
156 int index = 0;
157 for (const auto &cInt : code) {
158 napi_value jsInt = Convert2JSValue(env, cInt);
159 napi_set_element(env, value, index++, jsInt);
160 }
161 return value;
162 }
163
Convert2JSValue(napi_env env,const std::vector<int32_t> & code)164 napi_value Convert2JSValue(napi_env env, const std::vector<int32_t> &code)
165 {
166 napi_value value = nullptr;
167 napi_create_array_with_length(env, code.size(), &value);
168 int index = 0;
169 for (const auto &cInt : code) {
170 napi_set_element(env, value, index++, Convert2JSValue(env, cInt));
171 }
172 return value;
173 }
174
Convert2JSValue(napi_env env,const std::vector<std::string> & ids)175 napi_value Convert2JSValue(napi_env env, const std::vector<std::string> &ids)
176 {
177 napi_value value = nullptr;
178 napi_create_array_with_length(env, ids.size(), &value);
179 int index = 0;
180 for (const auto &id : ids) {
181 napi_set_element(env, value, index++, Convert2JSValue(env, id));
182 }
183 return value;
184 }
185
Convert2JSHeadersAndBody(napi_env env,const std::map<std::string,std::string> & header,const std::vector<uint8_t> & bodyBytes,bool isSeparate)186 napi_value Convert2JSHeadersAndBody(napi_env env, const std::map<std::string, std::string> &header,
187 const std::vector<uint8_t> &bodyBytes, bool isSeparate)
188 {
189 napi_value headers = nullptr;
190 napi_create_object(env, &headers);
191 for (const auto &cInt : header) {
192 napi_set_named_property(env, headers, cInt.first.c_str(), Convert2JSValue(env, cInt.second));
193 }
194 napi_value body = nullptr;
195 if (Utf8Utils::RunUtf8Validation(bodyBytes)) {
196 napi_create_string_utf8(env, reinterpret_cast<const char *>(bodyBytes.data()), bodyBytes.size(), &body);
197 } else {
198 uint8_t *data = nullptr;
199 napi_create_arraybuffer(env, bodyBytes.size(), reinterpret_cast<void **>(&data), &body);
200 if (memcpy_s(data, bodyBytes.size(), bodyBytes.data(), bodyBytes.size()) != EOK) {
201 if (bodyBytes.size() > 0) {
202 REQUEST_HILOGW("Body data memcpy_s error");
203 }
204 }
205 }
206
207 if (isSeparate) {
208 napi_value object = nullptr;
209 napi_create_object(env, &object);
210 napi_set_named_property(env, object, "headers", headers);
211 napi_set_named_property(env, object, "body", body);
212 return object;
213 } else {
214 napi_set_named_property(env, headers, "body", body);
215 return headers;
216 }
217 }
218
Convert2JSValue(napi_env env,const std::map<std::string,std::string> & code)219 napi_value Convert2JSValue(napi_env env, const std::map<std::string, std::string> &code)
220 {
221 napi_value object = nullptr;
222 napi_create_object(env, &object);
223 for (const auto &cInt : code) {
224 napi_set_named_property(env, object, cInt.first.c_str(), Convert2JSValue(env, cInt.second));
225 }
226 return object;
227 }
228
Convert2JSValue(napi_env env,const std::string & str)229 napi_value Convert2JSValue(napi_env env, const std::string &str)
230 {
231 napi_value value = nullptr;
232 if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
233 return nullptr;
234 }
235 return value;
236 }
237
Convert2JSValue(napi_env env,const std::vector<TaskState> & taskStates)238 napi_value Convert2JSValue(napi_env env, const std::vector<TaskState> &taskStates)
239 {
240 napi_value value = nullptr;
241 napi_create_array_with_length(env, taskStates.size(), &value);
242 int index = 0;
243 for (const auto &taskState : taskStates) {
244 napi_value jsTaskState = nullptr;
245 napi_create_object(env, &jsTaskState);
246 napi_set_named_property(env, jsTaskState, "path", Convert2JSValue(env, taskState.path));
247 napi_set_named_property(env, jsTaskState, "responseCode", Convert2JSValue(env, taskState.responseCode));
248 napi_set_named_property(env, jsTaskState, "message", Convert2JSValue(env, taskState.message));
249 napi_set_element(env, value, index++, jsTaskState);
250 }
251 return value;
252 }
253
Convert2JSValue(napi_env env,const Progress & progress)254 napi_value Convert2JSValue(napi_env env, const Progress &progress)
255 {
256 napi_value value = nullptr;
257 napi_create_object(env, &value);
258 napi_set_named_property(env, value, "state", Convert2JSValue(env, static_cast<uint32_t>(progress.state)));
259 napi_set_named_property(env, value, "index", Convert2JSValue(env, progress.index));
260 napi_set_named_property(env, value, "processed", Convert2JSValue(env, progress.processed));
261 napi_set_named_property(env, value, "sizes", Convert2JSValue(env, progress.sizes));
262 napi_set_named_property(
263 env, value, "extras", Convert2JSHeadersAndBody(env, progress.extras, progress.bodyBytes, false));
264 return value;
265 }
266
Convert2JSValue(napi_env env,const std::vector<FileSpec> & files,const std::vector<FormItem> & forms)267 napi_value Convert2JSValue(napi_env env, const std::vector<FileSpec> &files, const std::vector<FormItem> &forms)
268 {
269 napi_value data = nullptr;
270 size_t filesLen = files.size();
271 size_t formsLen = forms.size();
272 napi_create_array_with_length(env, filesLen + formsLen, &data);
273 size_t i = 0;
274 for (; i < formsLen; i++) {
275 napi_value object = nullptr;
276 napi_create_object(env, &object);
277 napi_set_named_property(env, object, "name", Convert2JSValue(env, forms[i].name));
278 napi_set_named_property(env, object, "value", Convert2JSValue(env, forms[i].value));
279 napi_set_element(env, data, i, object);
280 }
281 for (size_t j = 0; j < filesLen; j++) {
282 napi_value fileSpec = nullptr;
283 napi_create_object(env, &fileSpec);
284 napi_set_named_property(env, fileSpec, "path", Convert2JSValue(env, files[j].uri));
285 napi_set_named_property(env, fileSpec, "mimeType", Convert2JSValue(env, files[j].type));
286 napi_set_named_property(env, fileSpec, "filename", Convert2JSValue(env, files[j].filename));
287 napi_value object = nullptr;
288 napi_create_object(env, &object);
289 napi_set_named_property(env, object, "name", Convert2JSValue(env, files[j].name));
290 napi_set_named_property(env, object, "value", fileSpec);
291 napi_set_element(env, data, i, object);
292 i++;
293 }
294 return data;
295 }
296
Convert2Broken(Reason code)297 uint32_t Convert2Broken(Reason code)
298 {
299 static std::map<Reason, Faults> InnerCodeToBroken = {
300 { REASON_OK, Faults::OTHERS },
301 { TASK_SURVIVAL_ONE_MONTH, Faults::OTHERS },
302 { WAITTING_NETWORK_ONE_DAY, Faults::OTHERS },
303 { STOPPED_NEW_FRONT_TASK, Faults::OTHERS },
304 { RUNNING_TASK_MEET_LIMITS, Faults::OTHERS },
305 { USER_OPERATION, Faults::OTHERS },
306 { APP_BACKGROUND_OR_TERMINATE, Faults::OTHERS },
307 { NETWORK_OFFLINE, Faults::DISCONNECTED },
308 { UNSUPPORTED_NETWORK_TYPE, Faults::OTHERS },
309 { BUILD_CLIENT_FAILED, Faults::PARAM },
310 { BUILD_REQUEST_FAILED, Faults::PARAM },
311 { GET_FILESIZE_FAILED, Faults::FSIO },
312 { CONTINUOUS_TASK_TIMEOUT, Faults::OTHERS },
313 { CONNECT_ERROR, Faults::TCP },
314 { REQUEST_ERROR, Faults::PROTOCOL },
315 { UPLOAD_FILE_ERROR, Faults::OTHERS },
316 { REDIRECT_ERROR, Faults::REDIRECT },
317 { PROTOCOL_ERROR, Faults::PROTOCOL },
318 { IO_ERROR, Faults::FSIO },
319 { UNSUPPORT_RANGE_REQUEST, Faults::PROTOCOL },
320 { OTHERS_ERROR, Faults::OTHERS },
321 { ACCOUNT_STOPPED, Faults::OTHERS },
322 { NETWORK_CHANGED, Faults::OTHERS },
323 { DNS, Faults::DNS },
324 { TCP, Faults::TCP },
325 { SSL, Faults::SSL },
326 { INSUFFICIENT_SPACE, Faults::OTHERS },
327 { NETWORK_APP, Faults::DISCONNECTED },
328 { NETWORK_ACCOUNT, Faults::DISCONNECTED },
329 { APP_ACCOUNT, Faults::OTHERS },
330 { NETWORK_APP_ACCOUNT, Faults::DISCONNECTED },
331 };
332 constexpr const int32_t detailVersion = 12;
333 auto iter = InnerCodeToBroken.find(code);
334 if (iter != InnerCodeToBroken.end()) {
335 int32_t sdkVersion = GetSdkApiVersion();
336 REQUEST_HILOGD("GetSdkApiVersion %{public}d", sdkVersion);
337 if (sdkVersion < detailVersion
338 && (iter->second == Faults::PARAM || iter->second == Faults::DNS || iter->second == Faults::TCP
339 || iter->second == Faults::SSL || iter->second == Faults::REDIRECT)) {
340 return static_cast<uint32_t>(Faults::OTHERS);
341 }
342 return static_cast<uint32_t>(iter->second);
343 }
344 return 0;
345 }
346
Convert2ReasonMsg(Reason code)347 std::string Convert2ReasonMsg(Reason code)
348 {
349 static std::map<Reason, std::string> ReasonMsg = {
350 { REASON_OK, REASON_OK_INFO },
351 { TASK_SURVIVAL_ONE_MONTH, TASK_SURVIVAL_ONE_MONTH_INFO },
352 { WAITTING_NETWORK_ONE_DAY, WAITTING_NETWORK_ONE_DAY_INFO },
353 { STOPPED_NEW_FRONT_TASK, STOPPED_NEW_FRONT_TASK_INFO },
354 { RUNNING_TASK_MEET_LIMITS, RUNNING_TASK_MEET_LIMITS_INFO },
355 { USER_OPERATION, USER_OPERATION_INFO },
356 { APP_BACKGROUND_OR_TERMINATE, APP_BACKGROUND_OR_TERMINATE_INFO },
357 { NETWORK_OFFLINE, NETWORK_OFFLINE_INFO },
358 { UNSUPPORTED_NETWORK_TYPE, UNSUPPORTED_NETWORK_TYPE_INFO },
359 { BUILD_CLIENT_FAILED, BUILD_CLIENT_FAILED_INFO },
360 { BUILD_REQUEST_FAILED, BUILD_REQUEST_FAILED_INFO },
361 { GET_FILESIZE_FAILED, GET_FILESIZE_FAILED_INFO },
362 { CONTINUOUS_TASK_TIMEOUT, CONTINUOUS_TASK_TIMEOUT_INFO },
363 { CONNECT_ERROR, CONNECT_ERROR_INFO },
364 { REQUEST_ERROR, REQUEST_ERROR_INFO },
365 { UPLOAD_FILE_ERROR, UPLOAD_FILE_ERROR_INFO },
366 { REDIRECT_ERROR, REDIRECT_ERROR_INFO },
367 { PROTOCOL_ERROR, PROTOCOL_ERROR_INFO },
368 { IO_ERROR, IO_ERROR_INFO },
369 { UNSUPPORT_RANGE_REQUEST, UNSUPPORT_RANGE_REQUEST_INFO },
370 { OTHERS_ERROR, OTHERS_ERROR_INFO },
371 { ACCOUNT_STOPPED, ACCOUNT_STOPPED_INFO },
372 { NETWORK_CHANGED, NETWORK_CHANGED_INFO },
373 { DNS, DNS_INFO },
374 { TCP, TCP_INFO },
375 { SSL, SSL_INFO },
376 { INSUFFICIENT_SPACE, INSUFFICIENT_SPACE_INFO },
377 { NETWORK_APP, NETWORK_APP_INFO },
378 { NETWORK_ACCOUNT, NETWORK_ACCOUNT_INFO },
379 { APP_ACCOUNT, APP_ACCOUNT_INFO },
380 { NETWORK_APP_ACCOUNT, NETWORK_ACCOUNT_APP_INFO },
381 };
382 auto iter = ReasonMsg.find(code);
383 if (iter != ReasonMsg.end()) {
384 return iter->second;
385 }
386 return "unknown";
387 }
388
Convert2JSValue(napi_env env,TaskInfo & taskInfo)389 napi_value Convert2JSValue(napi_env env, TaskInfo &taskInfo)
390 {
391 napi_value value = nullptr;
392 napi_create_object(env, &value);
393 if (taskInfo.withSystem) {
394 napi_set_named_property(env, value, "uid", Convert2JSValue(env, taskInfo.uid));
395 napi_set_named_property(env, value, "bundle", Convert2JSValue(env, taskInfo.bundle));
396 taskInfo.url = "";
397 taskInfo.data = "";
398 if (taskInfo.action == Action::UPLOAD) {
399 taskInfo.files.clear();
400 taskInfo.forms.clear();
401 }
402 }
403 napi_set_named_property(env, value, "url", Convert2JSValue(env, taskInfo.url));
404 napi_set_named_property(env, value, "saveas", Convert2JSValue(env, GetSaveas(taskInfo.files, taskInfo.action)));
405 if (taskInfo.action == Action::DOWNLOAD) {
406 napi_set_named_property(env, value, "data", Convert2JSValue(env, taskInfo.data));
407 } else {
408 napi_set_named_property(env, value, "data", Convert2JSValue(env, taskInfo.files, taskInfo.forms));
409 }
410 napi_set_named_property(env, value, "tid", Convert2JSValue(env, taskInfo.tid));
411 napi_set_named_property(env, value, "title", Convert2JSValue(env, taskInfo.title));
412 napi_set_named_property(env, value, "description", Convert2JSValue(env, taskInfo.description));
413 napi_set_named_property(env, value, "action", Convert2JSValue(env, static_cast<uint32_t>(taskInfo.action)));
414 napi_set_named_property(env, value, "mode", Convert2JSValue(env, static_cast<uint32_t>(taskInfo.mode)));
415 napi_set_named_property(env, value, "mimeType", Convert2JSValue(env, taskInfo.mimeType));
416 napi_set_named_property(env, value, "progress", Convert2JSValue(env, taskInfo.progress));
417 napi_set_named_property(env, value, "gauge", Convert2JSValue(env, taskInfo.gauge));
418 napi_set_named_property(env, value, "priority", Convert2JSValue(env, taskInfo.priority));
419 napi_set_named_property(env, value, "ctime", Convert2JSValue(env, taskInfo.ctime));
420 napi_set_named_property(env, value, "mtime", Convert2JSValue(env, taskInfo.mtime));
421 napi_set_named_property(env, value, "retry", Convert2JSValue(env, taskInfo.retry));
422 napi_set_named_property(env, value, "tries", Convert2JSValue(env, taskInfo.tries));
423 if (taskInfo.code == Reason::REASON_OK) {
424 napi_value value1 = nullptr;
425 napi_get_null(env, &value1);
426 napi_set_named_property(env, value, "faults", value1);
427 } else {
428 napi_set_named_property(env, value, "faults", Convert2JSValue(env, Convert2Broken(taskInfo.code)));
429 }
430 napi_set_named_property(env, value, "reason", Convert2JSValue(env, Convert2ReasonMsg(taskInfo.code)));
431 napi_set_named_property(env, value, "extras", Convert2JSValue(env, taskInfo.extras));
432 return value;
433 }
434
Convert2JSValueConfig(napi_env env,Config & config)435 napi_value Convert2JSValueConfig(napi_env env, Config &config)
436 {
437 napi_value value = nullptr;
438 napi_create_object(env, &value);
439 napi_set_named_property(env, value, "action", Convert2JSValue(env, static_cast<uint32_t>(config.action)));
440 napi_set_named_property(env, value, "url", Convert2JSValue(env, config.url));
441 napi_set_named_property(env, value, "title", Convert2JSValue(env, config.title));
442 napi_set_named_property(env, value, "description", Convert2JSValue(env, config.description));
443 napi_set_named_property(env, value, "mode", Convert2JSValue(env, static_cast<uint32_t>(config.mode)));
444 napi_set_named_property(env, value, "overwrite", Convert2JSValue(env, config.overwrite));
445 napi_set_named_property(env, value, "method", Convert2JSValue(env, config.method));
446 napi_set_named_property(env, value, "headers", Convert2JSValue(env, config.headers));
447 if (config.action == Action::DOWNLOAD) {
448 napi_set_named_property(env, value, "data", Convert2JSValue(env, config.data));
449 } else {
450 napi_set_named_property(env, value, "data", Convert2JSValue(env, config.files, config.forms));
451 }
452 napi_set_named_property(env, value, "saveas", Convert2JSValue(env, config.saveas));
453 napi_set_named_property(env, value, "network", Convert2JSValue(env, static_cast<uint32_t>(config.network)));
454 napi_set_named_property(env, value, "metered", Convert2JSValue(env, config.metered));
455 napi_set_named_property(env, value, "roaming", Convert2JSValue(env, config.roaming));
456 napi_set_named_property(env, value, "retry", Convert2JSValue(env, config.retry));
457 napi_set_named_property(env, value, "redirect", Convert2JSValue(env, config.redirect));
458 napi_set_named_property(env, value, "index", Convert2JSValue(env, config.index));
459 napi_set_named_property(env, value, "begins", Convert2JSValue(env, config.begins));
460 napi_set_named_property(env, value, "ends", Convert2JSValue(env, config.ends));
461 napi_set_named_property(env, value, "priority", Convert2JSValue(env, config.priority));
462 napi_set_named_property(env, value, "gauge", Convert2JSValue(env, config.gauge));
463 napi_set_named_property(env, value, "precise", Convert2JSValue(env, config.precise));
464 if (config.token != "null") {
465 napi_set_named_property(env, value, "token", Convert2JSValue(env, config.token));
466 }
467 napi_set_named_property(env, value, "extras", Convert2JSValue(env, config.extras));
468 return value;
469 }
470
Convert2JSValue(napi_env env,const std::shared_ptr<Response> & response)471 napi_value Convert2JSValue(napi_env env, const std::shared_ptr<Response> &response)
472 {
473 napi_value value = nullptr;
474 napi_create_object(env, &value);
475 napi_set_named_property(env, value, "version", Convert2JSValue(env, response->version));
476 napi_set_named_property(env, value, "statusCode", Convert2JSValue(env, response->statusCode));
477 napi_set_named_property(env, value, "reason", Convert2JSValue(env, response->reason));
478 napi_set_named_property(env, value, "headers", Convert2JSHeaders(env, response->headers));
479 return value;
480 }
481
Convert2JSHeaders(napi_env env,const std::map<std::string,std::vector<std::string>> & headers)482 napi_value Convert2JSHeaders(napi_env env, const std::map<std::string, std::vector<std::string>> &headers)
483 {
484 napi_value value = nullptr;
485 napi_value value2 = nullptr;
486 napi_value global = nullptr;
487 napi_value mapConstructor = nullptr;
488 napi_value mapSet = nullptr;
489 const uint32_t paramNumber = 2;
490 napi_value args[paramNumber] = { 0 };
491
492 napi_status status = napi_get_global(env, &global);
493 if (status != napi_ok) {
494 REQUEST_HILOGE("response napi_get_global failed");
495 return nullptr;
496 }
497
498 status = napi_get_named_property(env, global, "Map", &mapConstructor);
499 if (status != napi_ok) {
500 REQUEST_HILOGE("response map failed");
501 return nullptr;
502 }
503
504 status = napi_new_instance(env, mapConstructor, 0, nullptr, &value);
505 if (status != napi_ok) {
506 REQUEST_HILOGE("response napi_new_instance failed");
507 return nullptr;
508 }
509
510 status = napi_get_named_property(env, value, "set", &mapSet);
511 if (status != napi_ok) {
512 REQUEST_HILOGE("response set failed");
513 return nullptr;
514 }
515
516 for (const auto &it : headers) {
517 args[0] = Convert2JSValue(env, it.first);
518 args[1] = Convert2JSValue(env, it.second);
519 status = napi_call_function(env, value, mapSet, paramNumber, args, &value2);
520 if (status != napi_ok) {
521 REQUEST_HILOGE("response napi_call_function failed, %{public}d", status);
522 return nullptr;
523 }
524 }
525 return value;
526 }
527
GetSaveas(const std::vector<FileSpec> & files,Action action)528 std::string GetSaveas(const std::vector<FileSpec> &files, Action action)
529 {
530 if (action == Action::UPLOAD) {
531 return "";
532 }
533 if (files.empty()) {
534 return "";
535 }
536 return files[0].uri;
537 }
538
Convert2Boolean(napi_env env,napi_value object,const std::string & propertyName)539 bool Convert2Boolean(napi_env env, napi_value object, const std::string &propertyName)
540 {
541 if (!HasNamedProperty(env, object, propertyName)) {
542 return false;
543 }
544 napi_value value = GetNamedProperty(env, object, propertyName);
545 if (GetValueType(env, value) != napi_boolean) {
546 return false;
547 }
548 bool ret = false;
549 NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
550 return ret;
551 }
552
Convert2Uint32(napi_env env,napi_value value)553 uint32_t Convert2Uint32(napi_env env, napi_value value)
554 {
555 uint32_t ret = 0;
556 NAPI_CALL_BASE(env, napi_get_value_uint32(env, value, &ret), 0);
557 return ret;
558 }
559
Convert2Uint32(napi_env env,napi_value object,const std::string & propertyName)560 uint32_t Convert2Uint32(napi_env env, napi_value object, const std::string &propertyName)
561 {
562 if (!HasNamedProperty(env, object, propertyName)) {
563 return 0;
564 }
565 napi_value value = GetNamedProperty(env, object, propertyName);
566 if (GetValueType(env, value) != napi_number) {
567 return 0;
568 }
569 return Convert2Uint32(env, value);
570 }
571
Convert2Int32(napi_env env,napi_value value)572 int32_t Convert2Int32(napi_env env, napi_value value)
573 {
574 int32_t ret = 0;
575 NAPI_CALL_BASE(env, napi_get_value_int32(env, value, &ret), 0);
576 return ret;
577 }
578
Convert2Int64(napi_env env,napi_value value)579 int64_t Convert2Int64(napi_env env, napi_value value)
580 {
581 int64_t ret = 0;
582 NAPI_CALL_BASE(env, napi_get_value_int64(env, value, &ret), 0);
583 return ret;
584 }
585
Convert2Int64(napi_env env,napi_value object,const std::string & propertyName)586 int64_t Convert2Int64(napi_env env, napi_value object, const std::string &propertyName)
587 {
588 if (!HasNamedProperty(env, object, propertyName)) {
589 return 0;
590 }
591 napi_value value = GetNamedProperty(env, object, propertyName);
592 if (GetValueType(env, value) != napi_number) {
593 return 0;
594 }
595 return Convert2Int64(env, value);
596 }
597
Convert2String(napi_env env,napi_value value)598 std::string Convert2String(napi_env env, napi_value value)
599 {
600 std::string result;
601 std::vector<char> str(MAX_STRING_LENGTH + 1, '\0');
602 size_t length = 0;
603 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, &str[0], MAX_STRING_LENGTH, &length), result);
604 if (length > 0) {
605 return result.append(&str[0], length);
606 }
607 return result;
608 }
609
Convert2String(napi_env env,napi_value object,const std::string & propertyName)610 std::string Convert2String(napi_env env, napi_value object, const std::string &propertyName)
611 {
612 if (!HasNamedProperty(env, object, propertyName)) {
613 return "";
614 }
615 napi_value value = GetNamedProperty(env, object, propertyName);
616 if (GetValueType(env, value) != napi_string) {
617 return "";
618 }
619 return Convert2String(env, value);
620 }
621
ThrowError(napi_env env,ExceptionErrorCode code,const std::string & msg,bool withErrCode)622 void ThrowError(napi_env env, ExceptionErrorCode code, const std::string &msg, bool withErrCode)
623 {
624 napi_value error = CreateBusinessError(env, code, msg, withErrCode);
625 napi_throw(env, error);
626 }
627
ConvertError(int32_t errorCode,ExceptionError & err)628 void ConvertError(int32_t errorCode, ExceptionError &err)
629 {
630 auto generateError = [&err](ExceptionErrorCode errorCode, const std::string &info) {
631 err.code = errorCode;
632 err.errInfo = info;
633 REQUEST_HILOGE("errorCode: %{public}d, errInfo: %{public}s", err.code, err.errInfo.c_str());
634 };
635
636 switch (errorCode) {
637 case E_UNLOADING_SA:
638 generateError(E_SERVICE_ERROR, "Service ability is quitting.");
639 break;
640 case E_IPC_SIZE_TOO_LARGE:
641 generateError(E_SERVICE_ERROR, "Ipc error.");
642 break;
643 case E_MIMETYPE_NOT_FOUND:
644 generateError(E_OTHER, "Mimetype not found.");
645 break;
646 case E_TASK_INDEX_TOO_LARGE:
647 generateError(E_TASK_NOT_FOUND, "Task index out of range.");
648 break;
649 default:
650 generateError(static_cast<ExceptionErrorCode>(errorCode), "");
651 break;
652 }
653 }
654
CreateBusinessError(napi_env env,ExceptionErrorCode errorCode,const std::string & errorMessage,bool withErrCode)655 napi_value CreateBusinessError(
656 napi_env env, ExceptionErrorCode errorCode, const std::string &errorMessage, bool withErrCode)
657 {
658 napi_value error = nullptr;
659 napi_value msg = nullptr;
660 auto iter = ErrorCodeToMsg.find(errorCode);
661 std::string strMsg = (iter != ErrorCodeToMsg.end() ? iter->second : "") + " " + errorMessage;
662 NAPI_CALL(env, napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg));
663 NAPI_CALL(env, napi_create_error(env, nullptr, msg, &error));
664 if (!withErrCode) {
665 return error;
666 }
667 napi_value code = nullptr;
668 NAPI_CALL(env, napi_create_uint32(env, static_cast<uint32_t>(errorCode), &code));
669 napi_set_named_property(env, error, "code", code);
670 return error;
671 }
672
GetValueType(napi_env env,napi_value value)673 napi_valuetype GetValueType(napi_env env, napi_value value)
674 {
675 if (value == nullptr) {
676 return napi_undefined;
677 }
678
679 napi_valuetype valueType = napi_undefined;
680 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
681 return valueType;
682 }
683
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)684 bool HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
685 {
686 bool hasProperty = false;
687 NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
688 return hasProperty;
689 }
690
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)691 napi_value GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
692 {
693 napi_value value = nullptr;
694 bool hasProperty = false;
695 NAPI_CALL(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty));
696 if (!hasProperty) {
697 return value;
698 }
699 NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
700 return value;
701 }
702
GetPropertyNames(napi_env env,napi_value object)703 std::vector<std::string> GetPropertyNames(napi_env env, napi_value object)
704 {
705 std::vector<std::string> ret;
706 napi_value names = nullptr;
707 NAPI_CALL_BASE(env, napi_get_property_names(env, object, &names), ret);
708 uint32_t length = 0;
709 NAPI_CALL_BASE(env, napi_get_array_length(env, names, &length), ret);
710 for (uint32_t index = 0; index < length; ++index) {
711 napi_value name = nullptr;
712 if (napi_get_element(env, names, index, &name) != napi_ok) {
713 continue;
714 }
715 if (GetValueType(env, name) != napi_string) {
716 continue;
717 }
718 ret.emplace_back(Convert2String(env, name));
719 }
720 return ret;
721 }
722
SetUint32Property(napi_env env,napi_value object,const std::string & name,uint32_t value)723 void SetUint32Property(napi_env env, napi_value object, const std::string &name, uint32_t value)
724 {
725 napi_value jsValue = Convert2JSValue(env, value);
726 if (GetValueType(env, jsValue) != napi_number) {
727 return;
728 }
729
730 napi_set_named_property(env, object, name.c_str(), jsValue);
731 }
732
SetInt64Property(napi_env env,napi_value object,const std::string & name,int64_t value)733 void SetInt64Property(napi_env env, napi_value object, const std::string &name, int64_t value)
734 {
735 napi_value jsValue = Convert2JSValue(env, value);
736 if (GetValueType(env, jsValue) != napi_number) {
737 return;
738 }
739
740 napi_set_named_property(env, object, name.c_str(), jsValue);
741 }
742
SetStringPropertyUtf8(napi_env env,napi_value object,const std::string & name,const std::string & value)743 void SetStringPropertyUtf8(napi_env env, napi_value object, const std::string &name, const std::string &value)
744 {
745 napi_value jsValue = Convert2JSValue(env, value);
746 if (GetValueType(env, jsValue) != napi_string) {
747 return;
748 }
749 napi_set_named_property(env, object, name.c_str(), jsValue);
750 }
751
CreateObject(napi_env env)752 napi_value CreateObject(napi_env env)
753 {
754 napi_value object = nullptr;
755 NAPI_CALL(env, napi_create_object(env, &object));
756 return object;
757 }
758
GetUndefined(napi_env env)759 napi_value GetUndefined(napi_env env)
760 {
761 napi_value undefined = nullptr;
762 NAPI_CALL(env, napi_get_undefined(env, &undefined));
763 return undefined;
764 }
765
CallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv)766 napi_value CallFunction(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv)
767 {
768 napi_value res = nullptr;
769 NAPI_CALL(env, napi_call_function(env, recv, func, argc, argv, &res));
770 return res;
771 }
772
ToLower(const std::string & s)773 std::string ToLower(const std::string &s)
774 {
775 std::string res = s;
776 std::transform(res.begin(), res.end(), res.begin(), tolower);
777 return res;
778 }
779
GetRequestAction(napi_env env,napi_value configValue)780 Action GetRequestAction(napi_env env, napi_value configValue)
781 {
782 if (HasNamedProperty(env, configValue, PARAM_KEY_METHOD) || HasNamedProperty(env, configValue, PARAM_KEY_FILES)
783 || HasNamedProperty(env, configValue, PARAM_KEY_DATA)) {
784 return Action::UPLOAD;
785 }
786 return Action::DOWNLOAD;
787 }
788
Convert2FileVector(napi_env env,napi_value jsFiles,const std::string & version)789 std::vector<FileSpec> Convert2FileVector(napi_env env, napi_value jsFiles, const std::string &version)
790 {
791 bool isArray = false;
792 napi_is_array(env, jsFiles, &isArray);
793 NAPI_ASSERT_BASE(env, isArray, "not array", {});
794 uint32_t length = 0;
795 napi_get_array_length(env, jsFiles, &length);
796 std::vector<FileSpec> files;
797 for (uint32_t i = 0; i < length; ++i) {
798 napi_value jsFile = nullptr;
799 napi_handle_scope scope = nullptr;
800 napi_open_handle_scope(env, &scope);
801 if (scope == nullptr) {
802 continue;
803 }
804 napi_get_element(env, jsFiles, i, &jsFile);
805 if (jsFile == nullptr) {
806 napi_close_handle_scope(env, scope);
807 continue;
808 }
809 FileSpec file;
810 bool ret = Convert2File(env, jsFile, file);
811 if (!ret) {
812 napi_close_handle_scope(env, scope);
813 continue;
814 }
815 files.push_back(file);
816 napi_close_handle_scope(env, scope);
817 }
818 return files;
819 }
820
Convert2File(napi_env env,napi_value jsFile,FileSpec & file)821 bool Convert2File(napi_env env, napi_value jsFile, FileSpec &file)
822 {
823 napi_value filename = GetNamedProperty(env, jsFile, "filename");
824 if (filename == nullptr) {
825 return false;
826 }
827 file.filename = Convert2String(env, filename);
828
829 napi_value name = GetNamedProperty(env, jsFile, "name");
830 if (name == nullptr) {
831 return false;
832 }
833 file.name = Convert2String(env, name);
834
835 napi_value uri = GetNamedProperty(env, jsFile, "uri");
836 if (uri == nullptr) {
837 return false;
838 }
839 file.uri = Convert2String(env, uri);
840
841 napi_value type = GetNamedProperty(env, jsFile, "type");
842 if (type == nullptr) {
843 return false;
844 }
845 file.type = Convert2String(env, type);
846 return true;
847 }
848
Convert2RequestDataVector(napi_env env,napi_value jsRequestDatas)849 std::vector<FormItem> Convert2RequestDataVector(napi_env env, napi_value jsRequestDatas)
850 {
851 bool isArray = false;
852 napi_is_array(env, jsRequestDatas, &isArray);
853 NAPI_ASSERT_BASE(env, isArray, "not array", {});
854 uint32_t length = 0;
855 napi_get_array_length(env, jsRequestDatas, &length);
856 std::vector<FormItem> requestDatas;
857 for (uint32_t i = 0; i < length; ++i) {
858 napi_value requestData = nullptr;
859 napi_get_element(env, jsRequestDatas, i, &requestData);
860 if (requestData == nullptr) {
861 continue;
862 }
863 requestDatas.push_back(Convert2RequestData(env, requestData));
864 }
865 return requestDatas;
866 }
867
Convert2RequestData(napi_env env,napi_value jsRequestData)868 FormItem Convert2RequestData(napi_env env, napi_value jsRequestData)
869 {
870 FormItem requestData;
871 napi_value value = nullptr;
872 napi_get_named_property(env, jsRequestData, "name", &value);
873 if (value != nullptr) {
874 requestData.name = Convert2String(env, value);
875 }
876 value = nullptr;
877 napi_get_named_property(env, jsRequestData, "value", &value);
878 if (value != nullptr) {
879 requestData.value = Convert2String(env, value);
880 }
881 return requestData;
882 }
883
IsPathValid(const std::string & filePath)884 bool IsPathValid(const std::string &filePath)
885 {
886 auto path = filePath.substr(0, filePath.rfind('/'));
887 char resolvedPath[PATH_MAX + 1] = { 0 };
888 if (path.length() > PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr
889 || strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
890 REQUEST_HILOGE("invalid file path!");
891 return false;
892 }
893 return true;
894 }
895
SHA256(const char * str,size_t len)896 std::string SHA256(const char *str, size_t len)
897 {
898 unsigned char hash[SHA256_DIGEST_LENGTH];
899 SHA256_CTX sha256;
900 SHA256_Init(&sha256);
901 SHA256_Update(&sha256, str, len);
902 SHA256_Final(hash, &sha256);
903 std::stringstream ss;
904 for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
905 // 2 means setting the width of the output.
906 ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
907 }
908 return ss.str();
909 }
910
ReadBytesFromFile(const std::string & filePath,std::vector<uint8_t> & fileData)911 void ReadBytesFromFile(const std::string &filePath, std::vector<uint8_t> &fileData)
912 {
913 // Ensure filePath validity.
914 std::ifstream inputFile(filePath.c_str(), std::ios::binary);
915 if (inputFile.is_open()) {
916 inputFile.seekg(0, std::ios::end);
917 fileData.resize(inputFile.tellg());
918 inputFile.seekg(0);
919 inputFile.read(reinterpret_cast<char *>(fileData.data()), fileData.size());
920 inputFile.close();
921 } else {
922 REQUEST_HILOGW("Read bytes from file, invalid file path!");
923 }
924 return;
925 }
926
RemoveFile(const std::string & filePath)927 void RemoveFile(const std::string &filePath)
928 {
929 auto removeFile = [filePath]() -> void {
930 std::remove(filePath.c_str());
931 return;
932 };
933 ffrt::submit(removeFile, {}, {}, ffrt::task_attr().name("Os_Request_Rm").qos(ffrt::qos_default));
934 }
935 } // namespace OHOS::Request::NapiUtils