1 /*
2 * Copyright (c) 2024 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 "cj_request_common.h"
17
18 #include <cstdlib>
19 #include <fstream>
20 #include <sstream>
21 #include "cj_request_ffi.h"
22 #include "ffrt.h"
23 #include "js_common.h"
24 #include "log.h"
25 #include "openssl/sha.h"
26 #include "parameter.h"
27 #include "securec.h"
28
29 namespace OHOS::CJSystemapi::Request {
30 using OHOS::Request::Action;
31 using OHOS::Request::ExceptionErrorCode;
32 using OHOS::Request::Faults;
33 using OHOS::Request::FileSpec;
34 using OHOS::Request::FormItem;
35 using OHOS::Request::Reason;
36
37 static constexpr const char *REASON_OK_INFO = "Task successful";
38 static constexpr const char *TASK_SURVIVAL_ONE_MONTH_INFO = "The task has not been completed for a month yet";
39 static constexpr const char *WAITTING_NETWORK_ONE_DAY_INFO = "The task waiting for network recovery has not been "
40 "completed for a day yet";
41 static constexpr const char *STOPPED_NEW_FRONT_TASK_INFO = "Stopped by a new front task";
42 static constexpr const char *RUNNING_TASK_MEET_LIMITS_INFO = "Too many task in running state";
43 static constexpr const char *USER_OPERATION_INFO = "User operation";
44 static constexpr const char *APP_BACKGROUND_OR_TERMINATE_INFO = "The app is background or terminate";
45 static constexpr const char *NETWORK_OFFLINE_INFO = "NetWork is offline";
46 static constexpr const char *UNSUPPORTED_NETWORK_TYPE_INFO = "NetWork type not meet the task config";
47 static constexpr const char *BUILD_CLIENT_FAILED_INFO = "Build client error";
48 static constexpr const char *BUILD_REQUEST_FAILED_INFO = "Build request error";
49 static constexpr const char *GET_FILESIZE_FAILED_INFO = "Failed because cannot get the file size from the server and "
50 "the precise is setted true by user";
51 static constexpr const char *CONTINUOUS_TASK_TIMEOUT_INFO = "Continuous processing task time out";
52 static constexpr const char *CONNECT_ERROR_INFO = "Connect error";
53 static constexpr const char *REQUEST_ERROR_INFO = "Request error";
54 static constexpr const char *UPLOAD_FILE_ERROR_INFO = "There are some files upload failed";
55 static constexpr const char *REDIRECT_ERROR_INFO = "Redirect error";
56 static constexpr const char *PROTOCOL_ERROR_INFO = "Http protocol error";
57 static constexpr const char *IO_ERROR_INFO = "Io Error";
58 static constexpr const char *UNSUPPORT_RANGE_REQUEST_INFO = "Range request not supported";
59 static constexpr const char *OTHERS_ERROR_INFO = "Some other error occured";
60 static constexpr const char *ACCOUNT_STOPPED_INFO = "Account stopped";
61 static constexpr const char *NETWORK_CHANGED_INFO = "Network changed";
62 static constexpr const char *DNS_INFO = "DNS error";
63 static constexpr const char *TCP_INFO = "TCP error";
64 static constexpr const char *SSL_INFO = "TSL/SSL error";
65 static constexpr const char *INSUFFICIENT_SPACE_INFO = "Insufficient space error";
66
ReadBytesFromFile(const std::string & filePath,std::vector<uint8_t> & fileData)67 void ReadBytesFromFile(const std::string &filePath, std::vector<uint8_t> &fileData)
68 {
69 // Ensure filePath validity.
70 std::ifstream inputFile(filePath.c_str(), std::ios::binary);
71 if (inputFile.is_open()) {
72 inputFile.seekg(0, std::ios::end);
73 fileData.resize(inputFile.tellg());
74 inputFile.seekg(0);
75 inputFile.read(reinterpret_cast<char *>(fileData.data()), fileData.size());
76 inputFile.close();
77 } else {
78 REQUEST_HILOGW("Read bytes from file, invalid file path!");
79 }
80 return;
81 }
82
MallocCString(const std::string & origin)83 char *MallocCString(const std::string &origin)
84 {
85 if (origin.empty()) {
86 return nullptr;
87 }
88 auto len = origin.length() + 1;
89 char *res = static_cast<char *>(malloc(sizeof(char) * len));
90 if (res == nullptr) {
91 return nullptr;
92 }
93 return std::char_traits<char>::copy(res, origin.c_str(), len);
94 }
95
IsPathValid(const std::string & filePath)96 bool IsPathValid(const std::string &filePath)
97 {
98 auto path = filePath.substr(0, filePath.rfind('/'));
99 char resolvedPath[PATH_MAX + 1] = {0};
100 if (path.length() > PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr ||
101 strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
102 REQUEST_HILOGE("invalid file path!");
103 return false;
104 }
105 return true;
106 }
107
SHA256(const char * str,size_t len)108 std::string SHA256(const char *str, size_t len)
109 {
110 unsigned char hash[SHA256_DIGEST_LENGTH];
111 SHA256_CTX sha256;
112 SHA256_Init(&sha256);
113 SHA256_Update(&sha256, str, len);
114 SHA256_Final(hash, &sha256);
115 std::stringstream ss;
116 for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
117 // 2 means setting hte width of the output.
118 ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
119 }
120 return ss.str();
121 }
122
ConvertError(int32_t errorCode)123 ExceptionError ConvertError(int32_t errorCode)
124 {
125 ExceptionError err;
126 auto generateError = [&err](ExceptionErrorCode errorCode, const std::string &info) {
127 err.code = errorCode;
128 err.errInfo = info;
129 REQUEST_HILOGE("errorCode: %{public}d, errInfo: %{public}s", err.code, err.errInfo.c_str());
130 };
131
132 switch (errorCode) {
133 case ExceptionErrorCode::E_UNLOADING_SA:
134 generateError(ExceptionErrorCode::E_SERVICE_ERROR, "Service ability is quitting.");
135 break;
136 case ExceptionErrorCode::E_IPC_SIZE_TOO_LARGE:
137 generateError(ExceptionErrorCode::E_SERVICE_ERROR, "Ipc error.");
138 break;
139 case ExceptionErrorCode::E_MIMETYPE_NOT_FOUND:
140 generateError(ExceptionErrorCode::E_OTHER, "Mimetype not found.");
141 break;
142 case ExceptionErrorCode::E_TASK_INDEX_TOO_LARGE:
143 generateError(ExceptionErrorCode::E_TASK_NOT_FOUND, "Task index out of range.");
144 break;
145 default:
146 generateError(static_cast<ExceptionErrorCode>(errorCode), "");
147 break;
148 }
149
150 return err;
151 }
152
Convert2CProgress(const Progress & in)153 CProgress Convert2CProgress(const Progress &in)
154 {
155 CProgress out = {0};
156 out.state = static_cast<uint32_t>(in.state);
157 out.index = in.index;
158 out.processed = in.processed;
159
160 if (in.sizes.size() > 0) {
161 out.sizeArr = static_cast<int64_t *>(malloc(sizeof(int64_t) * in.sizes.size()));
162 if (out.sizeArr == nullptr) {
163 return out;
164 }
165 for (std::vector<long>::size_type i = 0; i < in.sizes.size(); ++i) {
166 out.sizeArr[i] = in.sizes[i];
167 }
168 out.sizeArrLen = static_cast<int64_t>(in.sizes.size());
169 }
170
171 if (in.extras.size() <= 0) {
172 return out;
173 }
174
175 out.extras.headers = static_cast<CHashStrPair *>(malloc(sizeof(CHashStrPair) * in.extras.size()));
176 if (out.extras.headers == nullptr) {
177 return out;
178 }
179
180 int index = 0;
181 for (auto iter = in.extras.begin(); iter != in.extras.end(); ++iter) {
182 CHashStrPair *elem = &out.extras.headers[index++];
183 elem->key = MallocCString(iter->first);
184 elem->value = MallocCString(iter->second);
185 }
186 out.extras.size = static_cast<int64_t>(in.extras.size());
187 return out;
188 }
189
Convert2CArrString(const std::vector<std::string> & v)190 CArrString Convert2CArrString(const std::vector<std::string> &v)
191 {
192 CArrString out = {};
193 if (v.empty()) {
194 return out;
195 }
196
197 out.head = static_cast<char **>(malloc(sizeof(char *) * v.size()));
198 if (out.head == nullptr) {
199 return out;
200 }
201
202 int64_t index = 0;
203 for (auto iter : v) {
204 out.head[index] = MallocCString(iter);
205 index++;
206 }
207 out.size = index;
208 return out;
209 }
210
Convert2CResponse(const std::shared_ptr<Response> & in)211 CResponse Convert2CResponse(const std::shared_ptr<Response> &in)
212 {
213 CResponse out = {0};
214 out.version = MallocCString(in->version);
215 out.statusCode = in->statusCode;
216 out.reason = MallocCString(in->reason);
217
218 if (in->headers.size() <= 0) {
219 return out;
220 }
221 CHttpHeaderHashPair *hashHead =
222 static_cast<CHttpHeaderHashPair *>(malloc(sizeof(CHttpHeaderHashPair) * in->headers.size()));
223 if (hashHead == nullptr) {
224 return out;
225 }
226
227 int64_t index = 0;
228 for (auto iter : in->headers) {
229 hashHead[index].key = MallocCString(iter.first);
230 hashHead[index].value = Convert2CArrString(iter.second);
231 index++;
232 }
233 out.headers.hashHead = hashHead;
234 out.headers.size = index;
235 return out;
236 }
237
RemoveFile(const std::string & filePath)238 void RemoveFile(const std::string &filePath)
239 {
240 auto removeFile = [filePath]() -> void {
241 std::remove(filePath.c_str());
242 return;
243 };
244 ffrt::submit(removeFile, {}, {}, ffrt::task_attr().name("Os_Request_Rm").qos(ffrt::qos_default));
245 }
246
GetSaveas(const std::vector<FileSpec> & files,Action action)247 std::string GetSaveas(const std::vector<FileSpec> &files, Action action)
248 {
249 if (action == Action::UPLOAD) {
250 return "";
251 }
252 if (files.empty()) {
253 return "";
254 }
255 return files[0].uri;
256 }
257
Convert2Broken(Reason code)258 uint32_t Convert2Broken(Reason code)
259 {
260 static std::map<Reason, Faults> InnerCodeToBroken = {
261 {Reason::REASON_OK, Faults::OTHERS},
262 {Reason::TASK_SURVIVAL_ONE_MONTH, Faults::OTHERS},
263 {Reason::WAITTING_NETWORK_ONE_DAY, Faults::OTHERS},
264 {Reason::STOPPED_NEW_FRONT_TASK, Faults::OTHERS},
265 {Reason::RUNNING_TASK_MEET_LIMITS, Faults::OTHERS},
266 {Reason::USER_OPERATION, Faults::OTHERS},
267 {Reason::APP_BACKGROUND_OR_TERMINATE, Faults::OTHERS},
268 {Reason::NETWORK_OFFLINE, Faults::DISCONNECTED},
269 {Reason::UNSUPPORTED_NETWORK_TYPE, Faults::OTHERS},
270 {Reason::BUILD_CLIENT_FAILED, Faults::PARAM},
271 {Reason::BUILD_REQUEST_FAILED, Faults::PARAM},
272 {Reason::GET_FILESIZE_FAILED, Faults::FSIO},
273 {Reason::CONTINUOUS_TASK_TIMEOUT, Faults::OTHERS},
274 {Reason::CONNECT_ERROR, Faults::TCP},
275 {Reason::REQUEST_ERROR, Faults::PROTOCOL},
276 {Reason::UPLOAD_FILE_ERROR, Faults::OTHERS},
277 {Reason::REDIRECT_ERROR, Faults::REDIRECT},
278 {Reason::PROTOCOL_ERROR, Faults::PROTOCOL},
279 {Reason::IO_ERROR, Faults::FSIO},
280 {Reason::UNSUPPORT_RANGE_REQUEST, Faults::PROTOCOL},
281 {Reason::OTHERS_ERROR, Faults::OTHERS},
282 {Reason::ACCOUNT_STOPPED, Faults::OTHERS},
283 {Reason::NETWORK_CHANGED, Faults::OTHERS},
284 {Reason::DNS, Faults::DNS},
285 {Reason::TCP, Faults::TCP},
286 {Reason::SSL, Faults::SSL},
287 {Reason::INSUFFICIENT_SPACE, Faults::OTHERS},
288 };
289 constexpr const int32_t detailVersion = 12;
290 auto iter = InnerCodeToBroken.find(code);
291 if (iter != InnerCodeToBroken.end()) {
292 int32_t sdkVersion = GetSdkApiVersion();
293 REQUEST_HILOGD("GetSdkApiVersion %{public}d", sdkVersion);
294 if (sdkVersion < detailVersion &&
295 (iter->second == Faults::PARAM || iter->second == Faults::DNS || iter->second == Faults::TCP ||
296 iter->second == Faults::SSL || iter->second == Faults::REDIRECT)) {
297 return static_cast<uint32_t>(Faults::OTHERS);
298 }
299 return static_cast<uint32_t>(iter->second);
300 }
301 return 0;
302 }
303
Convert2ReasonMsg(Reason code)304 std::string Convert2ReasonMsg(Reason code)
305 {
306 static std::map<Reason, std::string> ReasonMsg = {
307 {Reason::REASON_OK, REASON_OK_INFO},
308 {Reason::TASK_SURVIVAL_ONE_MONTH, TASK_SURVIVAL_ONE_MONTH_INFO},
309 {Reason::WAITTING_NETWORK_ONE_DAY, WAITTING_NETWORK_ONE_DAY_INFO},
310 {Reason::STOPPED_NEW_FRONT_TASK, STOPPED_NEW_FRONT_TASK_INFO},
311 {Reason::RUNNING_TASK_MEET_LIMITS, RUNNING_TASK_MEET_LIMITS_INFO},
312 {Reason::USER_OPERATION, USER_OPERATION_INFO},
313 {Reason::APP_BACKGROUND_OR_TERMINATE, APP_BACKGROUND_OR_TERMINATE_INFO},
314 {Reason::NETWORK_OFFLINE, NETWORK_OFFLINE_INFO},
315 {Reason::UNSUPPORTED_NETWORK_TYPE, UNSUPPORTED_NETWORK_TYPE_INFO},
316 {Reason::BUILD_CLIENT_FAILED, BUILD_CLIENT_FAILED_INFO},
317 {Reason::BUILD_REQUEST_FAILED, BUILD_REQUEST_FAILED_INFO},
318 {Reason::GET_FILESIZE_FAILED, GET_FILESIZE_FAILED_INFO},
319 {Reason::CONTINUOUS_TASK_TIMEOUT, CONTINUOUS_TASK_TIMEOUT_INFO},
320 {Reason::CONNECT_ERROR, CONNECT_ERROR_INFO},
321 {Reason::REQUEST_ERROR, REQUEST_ERROR_INFO},
322 {Reason::UPLOAD_FILE_ERROR, UPLOAD_FILE_ERROR_INFO},
323 {Reason::REDIRECT_ERROR, REDIRECT_ERROR_INFO},
324 {Reason::PROTOCOL_ERROR, PROTOCOL_ERROR_INFO},
325 {Reason::IO_ERROR, IO_ERROR_INFO},
326 {Reason::UNSUPPORT_RANGE_REQUEST, UNSUPPORT_RANGE_REQUEST_INFO},
327 {Reason::OTHERS_ERROR, OTHERS_ERROR_INFO},
328 {Reason::ACCOUNT_STOPPED, ACCOUNT_STOPPED_INFO},
329 {Reason::NETWORK_CHANGED, NETWORK_CHANGED_INFO},
330 {Reason::DNS, DNS_INFO},
331 {Reason::TCP, TCP_INFO},
332 {Reason::SSL, SSL_INFO},
333 {Reason::INSUFFICIENT_SPACE, INSUFFICIENT_SPACE_INFO},
334 };
335 auto iter = ReasonMsg.find(code);
336 if (iter != ReasonMsg.end()) {
337 return iter->second;
338 }
339 return "unknown";
340 }
341
Convert2CHashStrArr(const std::map<std::string,std::string> & extras)342 CHashStrArr Convert2CHashStrArr(const std::map<std::string, std::string> &extras)
343 {
344 CHashStrArr out = {NULL};
345 size_t size = extras.size();
346 if (size == 0 || size > std::numeric_limits<size_t>::max() / sizeof(CHashStrPair)) {
347 return out;
348 }
349
350 out.headers = static_cast<CHashStrPair *>(malloc(sizeof(CHashStrPair) * size));
351 if (out.headers == nullptr) {
352 return out;
353 }
354
355 size_t i = 0;
356 for (const auto &it : extras) {
357 out.headers[i].key = MallocCString(it.first);
358 out.headers[i].value = MallocCString(it.second);
359 ++i;
360 }
361 out.size = static_cast<int64_t>(i);
362 return out;
363 }
364
Convert2CFormItemArr(const std::vector<FileSpec> & files,const std::vector<FormItem> & forms)365 CFormItemArr Convert2CFormItemArr(const std::vector<FileSpec> &files, const std::vector<FormItem> &forms)
366 {
367 CFormItemArr out = {NULL};
368 size_t filesLen = files.size();
369 size_t formsLen = forms.size();
370 size_t len = filesLen + formsLen;
371 if (len == 0) {
372 return out;
373 }
374
375 out.head = static_cast<CFormItem *>(malloc(sizeof(CFormItem) * len));
376 if (out.head == NULL) {
377 return out;
378 }
379 memset_s(out.head, sizeof(CFormItem) * len, 0, sizeof(CFormItem) * len);
380 size_t i = 0;
381 for (; i < formsLen; ++i) {
382 out.head[i].name = MallocCString(forms[i].name);
383 out.head[i].value.str = MallocCString(forms[i].value);
384 out.head[i].value.type = CFORM_ITEM_VALUE_TYPE_STRING;
385 }
386
387 for (size_t j = 0; j < filesLen; ++j) {
388 out.head[i].name = MallocCString(files[j].name);
389 out.head[i].value.file.path = MallocCString(files[j].uri);
390 out.head[i].value.file.mimeType = MallocCString(files[j].type);
391 out.head[i].value.file.filename = MallocCString(files[j].filename);
392 out.head[i].value.type = CFORM_ITEM_VALUE_TYPE_FILE;
393 ++i;
394 }
395
396 out.size = static_cast<int64_t>(i);
397 return out;
398 }
399
400 } // namespace OHOS::CJSystemapi::Request
401