1 /*
2 * Copyright (c) 2022 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 "upload_task.h"
17
18 #include <thread>
19
20 #include "curl/curl.h"
21 #include "curl/easy.h"
22 #include "hisysevent.h"
23 #include "hitrace_meter.h"
24
25 namespace OHOS::Request::Upload {
UploadTask(std::shared_ptr<UploadConfig> & uploadConfig)26 UploadTask::UploadTask(std::shared_ptr<UploadConfig> &uploadConfig)
27 {
28 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "UploadTask. In.");
29 uploadConfig_ = uploadConfig;
30 curlAdp_ = nullptr;
31 state_ = STATE_INIT;
32 uploadedSize_ = 0;
33 totalSize_ = 0;
34 progressCallback_ = nullptr;
35 headerReceiveCallback_ = nullptr;
36 failCallback_ = nullptr;
37 completeCallback_ = nullptr;
38 context_ = nullptr;
39 isRemoved_ = false;
40 }
41
~UploadTask()42 UploadTask::~UploadTask()
43 {
44 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "~UploadTask. In.");
45 std::lock_guard<std::mutex> guard(mutex_);
46 progressCallback_ = nullptr;
47 headerReceiveCallback_ = nullptr;
48 failCallback_ = nullptr;
49 completeCallback_ = nullptr;
50 if (!isRemoved_) {
51 Remove();
52 }
53 }
54
Remove()55 bool UploadTask::Remove()
56 {
57 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "Remove. In.");
58 std::lock_guard<std::mutex> guard(removeMutex_);
59 isRemoved_ = true;
60 if (curlAdp_ != nullptr) {
61 curlAdp_->Remove();
62 }
63 ClearFileArray();
64 return true;
65 }
66
On(Type type,void * callback)67 void UploadTask::On(Type type, void *callback)
68 {
69 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "On. In.");
70 std::lock_guard<std::mutex> guard(mutex_);
71 SetCallback(type, callback);
72 }
73
Off(Type type,void * callback)74 void UploadTask::Off(Type type, void *callback)
75 {
76 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "Off. In.");
77
78 std::lock_guard<std::mutex> guard(mutex_);
79 if (callback == nullptr) {
80 return;
81 }
82
83 if (type == TYPE_PROGRESS_CALLBACK && progressCallback_ != nullptr) {
84 (static_cast<IProgressCallback *>(callback))->Progress(uploadedSize_, totalSize_);
85 }
86 if (type == TYPE_HEADER_RECEIVE_CALLBACK && headerReceiveCallback_ != nullptr) {
87 (static_cast<IHeaderReceiveCallback *>(callback))->HeaderReceive(header_);
88 }
89 if (type == TYPE_COMPLETE_CALLBACK && completeCallback_ != nullptr) {
90 (static_cast<INotifyCallback *>(callback))->Notify(taskStates_);
91 }
92 if (type == TYPE_FAIL_CALLBACK && failCallback_ != nullptr) {
93 (static_cast<INotifyCallback *>(callback))->Notify(taskStates_);
94 }
95 SetCallback(type, nullptr);
96 }
97
SetCallback(Type type,void * callback)98 void UploadTask::SetCallback(Type type, void *callback)
99 {
100 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "SetCallback. In.");
101 if (type == TYPE_PROGRESS_CALLBACK) {
102 progressCallback_ = (IProgressCallback *)callback;
103 if (progressCallback_ && uploadedSize_ > 0) {
104 progressCallback_->Progress(uploadedSize_, totalSize_);
105 }
106 } else if (type == TYPE_HEADER_RECEIVE_CALLBACK) {
107 headerReceiveCallback_ = (IHeaderReceiveCallback *)callback;
108 if (headerReceiveCallback_ && headerArray_.empty() == false) {
109 for (auto header : headerArray_) {
110 if (header.length() > 0) {
111 headerReceiveCallback_->HeaderReceive(header);
112 }
113 }
114 headerArray_.clear();
115 }
116 } else if (type == TYPE_FAIL_CALLBACK) {
117 failCallback_ = (INotifyCallback *)callback;
118 if (failCallback_ && state_ == STATE_FAILURE) {
119 failCallback_->Notify(taskStates_);
120 }
121 } else if (type == TYPE_COMPLETE_CALLBACK) {
122 completeCallback_ = (INotifyCallback *)callback;
123 if (completeCallback_ && state_ == STATE_SUCCESS) {
124 completeCallback_->Notify(taskStates_);
125 }
126 } else {
127 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "SetCallback. type[%{public}d] not match.", type);
128 }
129 }
130
SetContext(std::shared_ptr<OHOS::AbilityRuntime::Context> context)131 void UploadTask::SetContext(std::shared_ptr<OHOS::AbilityRuntime::Context> context)
132 {
133 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "SetContext. In.");
134 context_ = context;
135 }
136
SetUploadProxy(std::shared_ptr<UploadTaskNapiV5> proxy)137 void UploadTask::SetUploadProxy(std::shared_ptr<UploadTaskNapiV5> proxy)
138 {
139 uploadProxy_ = proxy;
140 }
141
Run(std::shared_ptr<Upload::UploadTask> task)142 void UploadTask::Run(std::shared_ptr<Upload::UploadTask> task)
143 {
144 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "Run. In.");
145 usleep(USLEEP_INTERVEL_BEFOR_RUN);
146 if (task == nullptr) {
147 UPLOAD_HILOGE(UPLOAD_MODULE_FRAMEWORK, "task == nullptr");
148 return;
149 }
150 task->OnRun();
151 std::lock_guard<std::mutex> guard(task->removeMutex_);
152 if (task->isRemoved_) {
153 task->SetUploadProxy(nullptr);
154 return;
155 }
156 if (task->uploadConfig_->protocolVersion == API5) {
157 if (task->uploadConfig_->fcomplete) {
158 task->uploadConfig_->fcomplete();
159 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "Complete.");
160 }
161 }
162 task->SetUploadProxy(nullptr);
163 }
164
InitFileArray()165 uint32_t UploadTask::InitFileArray()
166 {
167 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "InitFileArray. In.");
168 unsigned int fileSize = 0;
169 FileData data;
170 FILE *file;
171 totalSize_ = 0;
172 uint32_t initResult = UPLOAD_OK;
173 ObtainFile obtainFile;
174 uint32_t index = 1;
175 for (auto f : uploadConfig_->files) {
176 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "filename is %{public}s", f.filename.c_str());
177 data.result = UPLOAD_ERRORCODE_UPLOAD_FAIL;
178 uint32_t ret = obtainFile.GetFile(&file, f.uri, fileSize, context_);
179 if (ret != UPLOAD_OK) {
180 initResult = data.result;
181 data.result = ret;
182 }
183
184 data.fp = file;
185 std::size_t position = f.uri.find_last_of("/");
186 if (position != std::string::npos) {
187 data.filename = std::string(f.uri, position + 1);
188 data.filename.erase(data.filename.find_last_not_of(" ") + 1);
189 }
190 data.name = f.name;
191 data.type = f.type;
192 data.fileIndex = index++;
193 data.adp = nullptr;
194 data.upsize = 0;
195 data.totalsize = fileSize;
196 data.list = nullptr;
197 data.headSendFlag = 0;
198 data.httpCode = 0;
199
200 fileDatas_.push_back(data);
201 totalSize_ += static_cast<int64_t>(fileSize);
202 }
203
204 return initResult;
205 }
206
StartUploadFile()207 uint32_t UploadTask::StartUploadFile()
208 {
209 if (isRemoved_) {
210 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "upload task removed");
211 return UPLOAD_TASK_REMOVED;
212 }
213 uint32_t ret = InitFileArray();
214 if (ret != UPLOAD_OK) {
215 return ret;
216 }
217 curlAdp_ = std::make_shared<CUrlAdp>(fileDatas_, uploadConfig_);
218 return curlAdp_->DoUpload(shared_from_this());
219 }
220
GetCodeMessage(uint32_t code)221 std::string UploadTask::GetCodeMessage(uint32_t code)
222 {
223 std::vector<std::pair<UploadErrorCode, std::string>> codeMap = {
224 { UPLOAD_OK, "file uploaded successfully" },
225 { UPLOAD_ERRORCODE_UNSUPPORT_URI, "file path error" },
226 { UPLOAD_ERRORCODE_GET_FILE_ERROR, "failed to get file" },
227 { UPLOAD_ERRORCODE_CONFIG_ERROR, "upload configuration error" },
228 { UPLOAD_ERRORCODE_UPLOAD_LIB_ERROR, "libcurl return error" },
229 { UPLOAD_ERRORCODE_UPLOAD_FAIL, "upload failed" },
230 { UPLOAD_ERRORCODE_UPLOAD_OUTTIME, "upload timeout" },
231 { UPLOAD_TASK_REMOVED, "upload task removed"}
232 };
233
234 for (const auto &it : codeMap) {
235 if (it.first == code) {
236 return it.second;
237 }
238 }
239 return "unknown";
240 }
241
OnRun()242 void UploadTask::OnRun()
243 {
244 std::string traceParam = "url:" + uploadConfig_->url + "file num:" + std::to_string(uploadConfig_->files.size());
245 HitraceScoped trace(HITRACE_TAG_MISC, "exec upload task " + traceParam);
246 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnRun. In.");
247 state_ = STATE_RUNNING;
248 uint32_t ret = StartUploadFile();
249 std::lock_guard<std::mutex> guard(removeMutex_);
250 if (!isRemoved_) {
251 if (ret != UPLOAD_OK) {
252 UPLOAD_HILOGE(UPLOAD_MODULE_FRAMEWORK, "ret != UPLOAD_OK");
253 OnFail();
254 ReportTaskFault(ret);
255 } else {
256 OnComplete();
257 }
258 ClearFileArray();
259 }
260 totalSize_ = 0;
261 }
262
ReportTaskFault(uint32_t ret) const263 void UploadTask::ReportTaskFault(uint32_t ret) const
264 {
265 uint32_t successCount = 0;
266 uint32_t failCount = 0;
267 for (auto &vmem : fileDatas_) {
268 if (vmem.result == UPLOAD_OK) {
269 successCount++;
270 } else {
271 failCount++;
272 }
273 }
274 OHOS::HiviewDFX::HiSysEvent::Write(OHOS::HiviewDFX::HiSysEvent::Domain::REQUEST, REQUEST_TASK_FAULT,
275 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, TASKS_TYPE, UPLOAD, TOTAL_FILE_NUM, fileDatas_.size(),
276 FAIL_FILE_NUM, failCount, SUCCESS_FILE_NUM, successCount, ERROR_INFO, static_cast<int>(ret));
277 }
278
OnProgress(curl_off_t ulnow)279 void UploadTask::OnProgress(curl_off_t ulnow)
280 {
281 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnProgress. In.");
282 if (isRemoved_) {
283 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnProgress isRemoved");
284 return;
285 }
286 if (ulnow == uploadedSize_) {
287 return;
288 }
289
290 std::lock_guard<std::mutex> guard(mutex_);
291 uploadedSize_ = ulnow;
292 if (uploadedSize_ == totalSize_) {
293 state_ = STATE_SUCCESS;
294 }
295 if (progressCallback_) {
296 progressCallback_->Progress(uploadedSize_, totalSize_);
297 }
298 }
299
OnHeaderReceive(const std::string & header)300 void UploadTask::OnHeaderReceive(const std::string &header)
301 {
302 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnHeaderReceive. In.");
303 if (isRemoved_) {
304 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnHeaderReceive isRemoved");
305 return;
306 }
307 std::lock_guard<std::mutex> guard(mutex_);
308 header_ = header;
309 if (headerReceiveCallback_) {
310 headerReceiveCallback_->HeaderReceive(header_);
311 } else {
312 headerArray_.push_back(header);
313 }
314 }
315
GetTaskStates()316 std::vector<TaskState> UploadTask::GetTaskStates()
317 {
318 std::vector<TaskState> taskStates;
319 TaskState taskState;
320 for (auto &vmem : fileDatas_) {
321 taskState = { vmem.filename, vmem.result, GetCodeMessage(vmem.result) };
322 taskStates.push_back(taskState);
323 }
324 return taskStates;
325 }
OnFail()326 void UploadTask::OnFail()
327 {
328 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnFail. In.");
329 if (isRemoved_) {
330 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnFail isRemoved");
331 return;
332 }
333 if (uploadConfig_->protocolVersion == API5) {
334 return;
335 }
336 std::lock_guard<std::mutex> guard(mutex_);
337 std::vector<TaskState> taskStates = GetTaskStates();
338 taskStates_ = taskStates;
339 state_ = STATE_FAILURE;
340 if (failCallback_) {
341 failCallback_->Notify(taskStates);
342 }
343 }
344
OnComplete()345 void UploadTask::OnComplete()
346 {
347 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnComplete. In.");
348 if (isRemoved_) {
349 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "OnComplete isRemoved");
350 return;
351 }
352 if (uploadConfig_->protocolVersion == API5) {
353 return;
354 }
355 std::lock_guard<std::mutex> guard(mutex_);
356 std::vector<TaskState> taskStates = GetTaskStates();
357 taskStates_ = taskStates;
358 state_ = STATE_SUCCESS;
359 if (completeCallback_) {
360 completeCallback_->Notify(taskStates);
361 }
362 }
363
ExecuteTask()364 void UploadTask::ExecuteTask()
365 {
366 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "ExecuteTask. In.");
367 thread_ = std::make_unique<std::thread>(UploadTask::Run, shared_from_this());
368 thread_handle_ = thread_->native_handle();
369 thread_->detach();
370 }
371
ClearFileArray()372 void UploadTask::ClearFileArray()
373 {
374 UPLOAD_HILOGD(UPLOAD_MODULE_FRAMEWORK, "ClearFileArray()");
375 if (fileDatas_.empty()) {
376 return;
377 }
378 for (auto &file : fileDatas_) {
379 if (file.fp != NULL) {
380 fclose(file.fp);
381 }
382 file.name = "";
383 }
384 fileDatas_.clear();
385 }
386 } // namespace OHOS::Request::Upload