• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "hilog/log.h"
17 #include "http_client.h"
18 #include "net_conn_client.h"
19 #include "request_preload.h"
20 
21 #include "base/network/download_manager.h"
22 
23 #define ACE_FORCE_EXPORT __attribute__((visibility("default")))
24 
25 #define ACE_CURL_EASY_SET_OPTION(handle, opt, data)            \
26     do {                                                       \
27         CURLcode result = curl_easy_setopt(handle, opt, data); \
28         if (result != CURLE_OK) {                              \
29             return false;                                      \
30         }                                                      \
31     } while (0)
32 
33 namespace OHOS::Ace {
34 namespace {
35 constexpr int32_t MAXIMUM_WAITING_PERIOD = 2800;
36 
37 #define PRINT_LOG(level, fmt, ...)                                                                               \
38     HILOG_IMPL(LOG_CORE, LOG_##level, 0xD00393A, "DownloadManager", "[%{public}d]" fmt, __LINE__, ##__VA_ARGS__) \
39 
40 #define LOGE(fmt, ...) PRINT_LOG(ERROR, fmt, ##__VA_ARGS__)
41 #define LOGW(fmt, ...) PRINT_LOG(WARN, fmt, ##__VA_ARGS__)
42 #define LOGI(fmt, ...) PRINT_LOG(INFO, fmt, ##__VA_ARGS__)
43 #define LOGD(fmt, ...) PRINT_LOG(DEBUG, fmt, ##__VA_ARGS__)
44 } // namespace
45 
46 // For sync download tasks, this period may cause image not able to be loaded.
47 // System detects appFreeze after 3s, which has higher priority
48 using NetStackRequest = NetStack::HttpClient::HttpClientRequest;
49 using NetStackResponse = NetStack::HttpClient::HttpClientResponse;
50 using NetStackError = NetStack::HttpClient::HttpClientError;
51 using NetStackTask = NetStack::HttpClient::HttpClientTask;
52 using NetStackTaskStatus = NetStack::HttpClient::TaskStatus;
53 
54 class ACE_FORCE_EXPORT DownloadManagerImpl : public DownloadManager {
55 public:
56     DownloadManagerImpl() = default;
~DownloadManagerImpl()57     ~DownloadManagerImpl()
58     {
59         if (isCurl_) {
60             curl_global_cleanup();
61         }
62     }
63 
Download(const std::string & url,std::vector<uint8_t> & dataOut)64     bool Download(const std::string& url, std::vector<uint8_t>& dataOut) override
65     {
66         // when calling, it is necessary to set it to true and call curl clean up method
67         // during download manager ohos object destruction
68         isCurl_ = true;
69         if (!Initialize()) {
70             return false;
71         }
72 
73         std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle(curl_easy_init(), &curl_easy_cleanup);
74         if (!handle) {
75             return false;
76         }
77 
78         dataOut.clear();
79         std::string errorStr;
80         errorStr.reserve(CURL_ERROR_SIZE);
81 
82         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str());
83         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEFUNCTION, OnWritingMemory);
84         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEDATA, &dataOut);
85         // Some servers don't like requests that are made without a user-agent field, so we provide one
86         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_USERAGENT, "libcurl-agent/1.0");
87         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str());
88         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_VERBOSE, 1L);
89         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_ERRORBUFFER, errorStr.data());
90 
91         ProxyInfo proxy;
92         if (GetProxy(proxy)) {
93             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXY, proxy.host.c_str());
94             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXYPORT, proxy.port);
95             if (!proxy.exclusions.empty()) {
96                 ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_NOPROXY, proxy.exclusions.c_str());
97             }
98             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
99             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_HTTPPROXYTUNNEL, 1L);
100         }
101 
102 #if defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM) || defined(PREVIEW)
103         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYPEER, 0L);
104         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYHOST, 0L);
105 #endif
106 
107         CURLcode result = curl_easy_perform(handle.get());
108         if (result != CURLE_OK) {
109             LOGE("Failed to download, url: [%{private}s], [%{public}s]", url.c_str(), curl_easy_strerror(result));
110             if (!errorStr.empty()) {
111                 LOGE("Failed to download reason: [%{public}s]", errorStr.c_str());
112             }
113             dataOut.clear();
114             return false;
115         }
116         dataOut.shrink_to_fit();
117         return true;
118     }
119 
Download(const std::string & url,const std::shared_ptr<DownloadResult> & downloadResult)120     bool Download(const std::string& url, const std::shared_ptr<DownloadResult>& downloadResult) override
121     {
122         NetStackRequest httpReq;
123         httpReq.SetHeader("Accept", "image/webp,*/*");
124         httpReq.SetURL(url);
125         auto& session = NetStack::HttpClient::HttpSession::GetInstance();
126         auto task = session.CreateTask(httpReq);
127         if (!task) {
128             return false;
129         }
130         std::shared_ptr<DownloadCondition> downloadCondition = std::make_shared<DownloadCondition>();
131         task->OnSuccess(
132             [downloadCondition, downloadResult](const NetStackRequest& request, const NetStackResponse& response) {
133                 {
134                     std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
135                     downloadResult->downloadSuccess = true;
136                     downloadResult->dataOut = std::move(response.GetResult());
137                 }
138                 downloadCondition->cv.notify_all();
139             });
140         task->OnCancel(
141             [downloadCondition, downloadResult](const NetStackRequest& request, const NetStackResponse& response) {
142                 {
143                     std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
144                     downloadResult->errorMsg.append("Http task of url ");
145                     downloadResult->errorMsg.append(request.GetURL());
146                     downloadResult->errorMsg.append(" cancelled by netStack");
147                     downloadResult->downloadSuccess = false;
148                 }
149                 downloadCondition->cv.notify_all();
150             });
151         task->OnFail([downloadCondition, downloadResult](
152                          const NetStackRequest& request, const NetStackResponse& response, const NetStackError& error) {
153             {
154                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
155                 downloadResult->errorMsg.append("Http task of url ");
156                 downloadResult->errorMsg.append(request.GetURL());
157                 downloadResult->errorMsg.append(" failed, response code ");
158                 auto responseCode = response.GetResponseCode();
159                 downloadResult->errorMsg.append(std::to_string(responseCode));
160                 downloadResult->errorMsg.append(", msg from netStack: ");
161                 downloadResult->errorMsg.append(error.GetErrorMessage());
162                 downloadResult->downloadSuccess = false;
163             }
164             downloadCondition->cv.notify_all();
165         });
166         auto result = task->Start();
167         return HandleDownloadResult(result, downloadCondition, downloadResult);
168     }
169 
DownloadAsync(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId,int32_t nodeId)170     bool DownloadAsync(
171         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override
172     {
173         NetStackRequest httpReq;
174         httpReq.SetHeader("Accept", "image/webp,*/*");
175         httpReq.SetURL(url);
176         auto& session = NetStack::HttpClient::HttpSession::GetInstance();
177         auto task = session.CreateTask(httpReq);
178         if (!task) {
179             return false;
180         }
181         task->OnSuccess(
182             [this, successCallback = downloadCallback.successCallback, failCallback = downloadCallback.failCallback,
183                 instanceId, url, nodeId](const NetStackRequest& request, const NetStackResponse& response) {
184                 if (response.GetResponseCode() != NetStack::HttpClient::ResponseCode::OK) {
185                     std::string errorMsg = "Http task of url " + request.GetURL() + " failed, response code " +
186                                            std::to_string(response.GetResponseCode());
187                     failCallback(errorMsg, true, instanceId);
188                     RemoveDownloadTask(url, nodeId, false);
189                     return;
190                 }
191                 LOGI("Async http task of url [%{private}s] success, the responseCode = %d", request.GetURL().c_str(),
192                     response.GetResponseCode());
193                 successCallback(std::move(response.GetResult()), true, instanceId);
194                 RemoveDownloadTask(url, nodeId, false);
195             });
196         task->OnCancel([this, cancelCallback = downloadCallback.cancelCallback, instanceId, url, nodeId](
197                            const NetStackRequest& request, const NetStackResponse& response) {
198             LOGI("Async Http task of url [%{private}s] cancelled by netStack", request.GetURL().c_str());
199             std::string errorMsg = "Http task of url " + request.GetURL() + " cancelled by netStack";
200             cancelCallback(errorMsg, true, instanceId);
201             RemoveDownloadTask(url, nodeId, false);
202         });
203         task->OnFail([this, failCallback = downloadCallback.failCallback, instanceId, url, nodeId](
204                          const NetStackRequest& request, const NetStackResponse& response, const NetStackError& error) {
205             LOGI("Async http task of url [%{private}s] failed, response code %{public}d, msg from netStack: "
206                  "[%{public}s]",
207                 request.GetURL().c_str(), response.GetResponseCode(), error.GetErrorMessage().c_str());
208             std::string errorMsg = "Http task of url " + request.GetURL() + " failed, response code " +
209                                    std::to_string(response.GetResponseCode()) +
210                                    ", msg from netStack: " + error.GetErrorMessage();
211             failCallback(errorMsg, true, instanceId);
212             RemoveDownloadTask(url, nodeId, false);
213         });
214         if (downloadCallback.onProgressCallback) {
215             task->OnProgress([onProgressCallback = downloadCallback.onProgressCallback, instanceId](
216                                  const NetStackRequest& request, u_long dlTotal, u_long dlNow, u_long ulTotal,
217                                  u_long ulNow) { onProgressCallback(dlTotal, dlNow, true, instanceId); });
218         }
219         AddDownloadTask(url, task, nodeId);
220         auto result = task->Start();
221         LOGI("download src [%{private}s] [%{public}s]", url.c_str(),
222             result ? " successfully" : " failed to download, please check netStack log");
223         return result;
224     }
225 
DownloadSync(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId,int32_t nodeId)226     bool DownloadSync(
227         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override
228     {
229         LOGI("DownloadSync task of [%{private}s] start", url.c_str());
230         NetStackRequest httpReq;
231         httpReq.SetHeader("Accept", "image/webp,*/*");
232         httpReq.SetURL(url);
233         auto& session = NetStack::HttpClient::HttpSession::GetInstance();
234         auto task = session.CreateTask(httpReq);
235         std::shared_ptr<DownloadCondition> downloadCondition = std::make_shared<DownloadCondition>();
236         if (!task) {
237             return false;
238         }
239         task->OnSuccess(
240             [this, downloadCondition, url, nodeId](const NetStackRequest& request, const NetStackResponse& response) {
241                 LOGI("Sync http task of url [%{private}s] success, the responseCode = %d", request.GetURL().c_str(),
242                     response.GetResponseCode());
243                 {
244                     std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
245                     downloadCondition->downloadSuccess = true;
246                     downloadCondition->dataOut = std::move(response.GetResult());
247                 }
248                 downloadCondition->cv.notify_all();
249                 RemoveDownloadTask(url, nodeId, false);
250             });
251         task->OnCancel(
252             [this, downloadCondition, url, nodeId](const NetStackRequest& request, const NetStackResponse& response) {
253                 LOGI("Sync Http task of url [%{private}s] cancelled", request.GetURL().c_str());
254                 {
255                     std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
256                     downloadCondition->errorMsg.append("Http task of url ");
257                     downloadCondition->errorMsg.append(request.GetURL());
258                     downloadCondition->errorMsg.append(" cancelled by netStack");
259                     downloadCondition->downloadSuccess = false;
260                 }
261                 downloadCondition->cv.notify_all();
262                 RemoveDownloadTask(url, nodeId, false);
263             });
264         task->OnFail(
265             [downloadCondition, url](const NetStackRequest& request, const NetStackResponse& response,
266                 const NetStackError& error) { OnFail(downloadCondition, request, response, error); });
267         if (downloadCallback.onProgressCallback) {
268             task->OnProgress([onProgressCallback = downloadCallback.onProgressCallback, instanceId](
269                                 const NetStackRequest& request, u_long dlTotal, u_long dlNow, u_long ulTotal,
270                                 u_long ulNow) { onProgressCallback(dlTotal, dlNow, false, instanceId); });
271         }
272         AddDownloadTask(url, task, nodeId);
273         auto result = task->Start();
274         return HandleDownloadResult(result, std::move(downloadCallback), downloadCondition, instanceId, url);
275     }
276 
DownloadAsyncWithPreload(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId,int32_t nodeId)277     bool DownloadAsyncWithPreload(
278         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override
279     {
280         auto innerCallback = std::make_unique<Request::PreloadCallback>();
281         innerCallback->OnSuccess = [this, successCallback = downloadCallback.successCallback,
282                                        failCallback = downloadCallback.failCallback, instanceId, url,
283                                        nodeId](const std::shared_ptr<Request::Data>&& data, const std::string& taskId) {
284             LOGI("Async http task of url [%{private}s-%{public}s] success", url.c_str(), taskId.c_str());
285             successCallback(std::move(std::string(data->bytes().data(), data->bytes().data() + data->bytes().length())),
286                 true, instanceId);
287             RemoveDownloadTaskWithPreload(url, nodeId, false);
288         };
289         innerCallback->OnCancel = [this, cancelCallback = downloadCallback.cancelCallback, url, nodeId]() {
290             LOGI("Async Http task of url [%{private}s] cancelled", url.c_str());
291             RemoveDownloadTaskWithPreload(url, nodeId, false);
292         };
293         innerCallback->OnFail = [this, failCallback = downloadCallback.failCallback, instanceId, url, nodeId](
294                                     const Request::PreloadError& error, const std::string& taskId) {
295             LOGI("ASync http task of url [%{private}s-%{public}s] failed, reason [%{private}s]", url.c_str(),
296                 taskId.c_str(), error.GetMessage().c_str());
297             std::string errorMsg = "Http task of url " + url + " failed, response code " +
298                                    std::to_string(error.GetCode()) + ", msg from netStack: " + error.GetMessage();
299             failCallback(errorMsg, true, instanceId);
300             RemoveDownloadTaskWithPreload(url, nodeId, false);
301         };
302 
303         if (downloadCallback.onProgressCallback) {
304             innerCallback->OnProgress = [onProgressCallback = downloadCallback.onProgressCallback, instanceId](
305                                             uint64_t dlNow, uint64_t dlTotal) {
306                 onProgressCallback(dlTotal, dlNow, true, instanceId);
307             };
308         }
309         auto handle = Request::Preload::GetInstance()->load(url, std::move(innerCallback));
310         bool isSuccess = (handle != nullptr);
311         if (isSuccess) {
312             AddDownloadTaskForPreload(url, handle, nodeId);
313         }
314         LOGI("Async http download src [%{private}s] [%{public}s]", url.c_str(),
315             isSuccess ? " successfully" : " failed to download, please check netStack log");
316         return isSuccess;
317     }
318 
fetchCachedResult(const std::string & url,std::string & result)319     bool fetchCachedResult(const std::string& url, std::string& result) override
320     {
321         auto data = Request::Preload::GetInstance()->fetch(url);
322         if (data.has_value()) {
323             result = std::string(data->bytes().data(), data->bytes().data() + data->bytes().length());
324             return true;
325         }
326         return false;
327     }
328 
DownloadSyncWithPreload(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId,int32_t nodeId)329     bool DownloadSyncWithPreload(
330         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override
331     {
332         auto innerCallback = std::make_unique<Request::PreloadCallback>();
333         auto downloadCondition = std::make_shared<DownloadCondition>();
334         innerCallback->OnSuccess = [this, downloadCondition, url, nodeId](
335                                        const std::shared_ptr<Request::Data>&& data, const std::string& taskId) {
336             LOGI("Sync http task of url [%{private}s-%{public}s] success", url.c_str(), taskId.c_str());
337             {
338                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
339                 downloadCondition->downloadSuccess = true;
340                 downloadCondition->dataOut =
341                     std::string(data->bytes().data(), data->bytes().data() + data->bytes().length());
342             }
343             downloadCondition->cv.notify_all();
344             RemoveDownloadTaskWithPreload(url, nodeId, false);
345         };
346         innerCallback->OnCancel = [this, downloadCondition, url, nodeId]() {
347             LOGI("Sync Http task of url [%{private}s] cancelled", url.c_str());
348             {
349                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
350                 downloadCondition->errorMsg.append("Http task of url ");
351                 downloadCondition->errorMsg.append(url.c_str());
352                 downloadCondition->errorMsg.append(" cancelled by netStack");
353                 downloadCondition->downloadSuccess = false;
354             }
355             downloadCondition->cv.notify_all();
356             RemoveDownloadTaskWithPreload(url, nodeId, false);
357         };
358         innerCallback->OnFail = [this, downloadCondition, url, nodeId](
359                                     const Request::PreloadError& error, const std::string& taskId) {
360             LOGI("Sync http task of url [%{private}s-%{public}s] failed, reason [%{private}s]", url.c_str(),
361                 taskId.c_str(), error.GetMessage().c_str());
362             {
363                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
364                 std::string errorMsg = "Http task of url " + url + " failed, response code " +
365                                        std::to_string(error.GetCode()) + ", msg from netStack: " + error.GetMessage();
366                 downloadCondition->downloadSuccess = false;
367             }
368             downloadCondition->cv.notify_all();
369             RemoveDownloadTaskWithPreload(url, nodeId, false);
370         };
371 
372         if (downloadCallback.onProgressCallback) {
373             innerCallback->OnProgress = [onProgressCallback = downloadCallback.onProgressCallback, instanceId](
374                                             uint64_t dlNow, uint64_t dlTotal) {
375                 onProgressCallback(dlTotal, dlNow, true, instanceId);
376             };
377         }
378         auto handle = Request::Preload::GetInstance()->load(url, std::move(innerCallback));
379         bool isSuccess = (handle != nullptr);
380         if (isSuccess) {
381             AddDownloadTaskForPreload(url, handle, nodeId);
382         }
383         return HandleDownloadResult(isSuccess, std::move(downloadCallback), downloadCondition, instanceId, url);
384     }
385 
OnFail(std::shared_ptr<DownloadCondition> downloadCondition,const NetStackRequest & request,const NetStackResponse & response,const NetStackError & error)386     static void OnFail(std::shared_ptr<DownloadCondition> downloadCondition, const NetStackRequest& request,
387         const NetStackResponse& response, const NetStackError& error)
388     {
389         LOGI("Sync Http task of url [%{private}s] failed, response code %{public}d, msg from netStack: [%{public}s]",
390             request.GetURL().c_str(), response.GetResponseCode(), error.GetErrorMessage().c_str());
391         {
392             std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
393             downloadCondition->errorMsg.append("Http task of url ");
394             downloadCondition->errorMsg.append(request.GetURL());
395             downloadCondition->errorMsg.append(" failed, response code ");
396             auto responseCode = response.GetResponseCode();
397             downloadCondition->errorMsg.append(std::to_string(responseCode));
398             downloadCondition->errorMsg.append(", msg from netStack: ");
399             downloadCondition->errorMsg.append(error.GetErrorMessage());
400             downloadCondition->downloadSuccess = false;
401         }
402         downloadCondition->cv.notify_all();
403     }
404 
RemoveDownloadTask(const std::string & url,int32_t nodeId,bool isCancel=true)405     bool RemoveDownloadTask(const std::string& url, int32_t nodeId, bool isCancel = true) override
406     {
407         std::scoped_lock lock(httpTaskMutex_);
408         auto urlKey = url + std::to_string(nodeId);
409         auto iter = httpTaskMap_.find(urlKey);
410         if (iter != httpTaskMap_.end()) {
411             auto task = iter->second;
412             if (task->GetStatus() == NetStackTaskStatus::RUNNING && isCancel) {
413                 LOGI("AceImage RemoveDownloadTask, url:%{private}s", url.c_str());
414                 task->Cancel();
415             }
416             httpTaskMap_.erase(iter);
417             return true;
418         }
419         return false;
420     }
421 
RemoveDownloadTaskWithPreload(const std::string & url,int32_t nodeId,bool isCancel=true)422     bool RemoveDownloadTaskWithPreload(const std::string& url, int32_t nodeId, bool isCancel = true) override
423     {
424         std::scoped_lock lock(httpHandleMutexForPreload_);
425         auto urlKey = url + std::to_string(nodeId);
426         auto iter = httpHandleMapForPreload_.find(urlKey);
427         if (iter != httpHandleMapForPreload_.end()) {
428             auto task = iter->second;
429             if (task->GetState() == Request::PreloadState::RUNNING && isCancel) {
430                 LOGI("AceImage RemoveDownloadHandle, url:%{private}s", url.c_str());
431                 task->Cancel();
432             }
433             httpHandleMapForPreload_.erase(iter);
434             return true;
435         }
436         return false;
437     }
438 
439 private:
440     struct ProxyInfo {
441         std::string host;
442         int32_t port = 0;
443         std::string exclusions;
444     };
445     std::mutex httpTaskMutex_;
446     std::unordered_map<std::string, std::shared_ptr<NetStackTask>> httpTaskMap_;
447     // use preload module to download the url
448     std::mutex httpHandleMutexForPreload_;
449     std::unordered_map<std::string, std::shared_ptr<Request::PreloadHandle>> httpHandleMapForPreload_;
450 
HandleDownloadResult(bool result,DownloadCallback && downloadCallback,const std::shared_ptr<DownloadCondition> & downloadCondition,int32_t instanceId,const std::string & url)451     bool HandleDownloadResult(bool result, DownloadCallback&& downloadCallback,
452         const std::shared_ptr<DownloadCondition>& downloadCondition, int32_t instanceId, const std::string& url)
453     {
454         if (!result) {
455             return result;
456         }
457         {
458             std::unique_lock<std::mutex> downloadLock(downloadCondition->downloadMutex);
459             // condition_variable is waiting for any of the success, cancel or failed to respond in sync mode
460             downloadCondition->cv.wait_for(
461                 downloadLock, std::chrono::milliseconds(MAXIMUM_WAITING_PERIOD), [downloadCondition] {
462                     return downloadCondition ? downloadCondition->downloadSuccess.has_value() : false;
463                 });
464         }
465         if (!downloadCondition->downloadSuccess.has_value()) {
466             LOGI("Sync Task of netstack with url [%{private}s] maximum waiting period exceed", url.c_str());
467         }
468         if (downloadCondition->downloadSuccess.value_or(false)) {
469             downloadCallback.successCallback(std::move(downloadCondition->dataOut), false, instanceId);
470         } else {
471             downloadCallback.failCallback(downloadCondition->errorMsg, false, instanceId);
472         }
473         return true;
474     }
475 
HandleDownloadResult(bool result,const std::shared_ptr<DownloadCondition> & downloadCondition,const std::shared_ptr<DownloadResult> & downloadResult)476     bool HandleDownloadResult(bool result, const std::shared_ptr<DownloadCondition>& downloadCondition,
477         const std::shared_ptr<DownloadResult>& downloadResult)
478     {
479         if (!result) {
480             return result;
481         }
482         {
483             std::unique_lock<std::mutex> downloadLock(downloadCondition->downloadMutex);
484             // condition_variable is waiting for any of the success, cancel or failed to respond in sync mode
485             downloadCondition->cv.wait_for(
486                 downloadLock, std::chrono::milliseconds(MAXIMUM_WAITING_PERIOD), [downloadCondition, downloadResult] {
487                     return downloadCondition ? downloadResult->downloadSuccess.has_value() : false;
488                 });
489         }
490         return true;
491     }
492 
IsContains(const std::string & url)493     bool IsContains(const std::string& url) override
494     {
495         return Request::Preload::GetInstance()->Contains(url);
496     }
497 
AddDownloadTask(const std::string & url,const std::shared_ptr<NetStackTask> & task,int32_t nodeId)498     void AddDownloadTask(const std::string& url, const std::shared_ptr<NetStackTask>& task, int32_t nodeId)
499     {
500         std::scoped_lock lock(httpTaskMutex_);
501         httpTaskMap_.emplace(url + std::to_string(nodeId), task);
502     }
503 
504     // use preload module to download the url
AddDownloadTaskForPreload(const std::string & url,const std::shared_ptr<Request::PreloadHandle> & handle,int32_t nodeId)505     void AddDownloadTaskForPreload(
506         const std::string& url, const std::shared_ptr<Request::PreloadHandle>& handle, int32_t nodeId)
507     {
508         std::scoped_lock lock(httpHandleMutexForPreload_);
509         httpHandleMapForPreload_.emplace(url + std::to_string(nodeId), handle);
510     }
511 
Initialize()512     bool Initialize()
513     {
514         if (initialized_) {
515             return true;
516         }
517 
518         std::lock_guard<std::mutex> lock(mutex_);
519         if (initialized_) {
520             return true;
521         }
522         if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
523             LOGE("Failed to initialize 'curl'");
524             return false;
525         }
526         initialized_ = true;
527         return true;
528     }
529 
OnWritingMemory(void * data,size_t size,size_t memBytes,void * userData)530     static size_t OnWritingMemory(void* data, size_t size, size_t memBytes, void* userData)
531     {
532         // size is always 1, for more details see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
533         auto& dataOut = *static_cast<std::vector<uint8_t>*>(userData);
534         auto chunkData = static_cast<uint8_t*>(data);
535         dataOut.insert(dataOut.end(), chunkData, chunkData + memBytes);
536         return memBytes;
537     }
538 
GetProxy(ProxyInfo & proxy)539     static bool GetProxy(ProxyInfo& proxy)
540     {
541         NetManagerStandard::HttpProxy httpProxy;
542         NetManagerStandard::NetConnClient::GetInstance().GetDefaultHttpProxy(httpProxy);
543         proxy.host = httpProxy.GetHost();
544         proxy.port = httpProxy.GetPort();
545 
546         auto exclusionList = httpProxy.GetExclusionList();
547         for (auto&& ex : exclusionList) {
548             proxy.exclusions.append(ex);
549             if (ex != exclusionList.back()) {
550                 proxy.exclusions.append(",");
551             }
552         }
553         return true;
554     }
555 
556     std::mutex mutex_;
557     bool initialized_ = false;
558     bool isCurl_ = false;
559 };
560 
OHOS_ACE_CreateDownloadManager()561 extern "C" ACE_FORCE_EXPORT void* OHOS_ACE_CreateDownloadManager()
562 {
563     return new DownloadManagerImpl();
564 }
565 } // namespace OHOS::Ace
566