• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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