• 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, { ImageErrorCode::GET_IMAGE_ASYNC_HTTP_FAILED, 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, { ImageErrorCode::GET_IMAGE_ASYNC_HTTP_CANCELLED, 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, { ImageErrorCode::GET_IMAGE_ASYNC_HTTP_FAILED, 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)277     bool DownloadAsyncWithPreload(
278         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId) override
279     {
280         auto innerCallback = std::make_unique<Request::PreloadCallback>();
281         innerCallback->OnSuccess = [this, successCallback = downloadCallback.successCallback,
282                                        failCallback = downloadCallback.failCallback, instanceId,
283                                        url](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, false);
288         };
289         innerCallback->OnCancel = [this, url]() {
290             LOGI("Async Http task of url [%{private}s] cancelled", url.c_str());
291             RemoveDownloadTaskWithPreload(url, false);
292         };
293         innerCallback->OnFail = [this, failCallback = downloadCallback.failCallback, instanceId, url](
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, { ImageErrorCode::GET_IMAGE_ASYNC_HTTP_FAILED, "async http task of uri failed." },
300                 true, instanceId);
301             RemoveDownloadTaskWithPreload(url, false);
302         };
303 
304         if (downloadCallback.onProgressCallback) {
305             innerCallback->OnProgress = [onProgressCallback = downloadCallback.onProgressCallback, instanceId](
306                                             uint64_t dlNow, uint64_t dlTotal) {
307                 onProgressCallback(dlTotal, dlNow, true, instanceId);
308             };
309         }
310         auto handle = Request::Preload::GetInstance()->load(url, std::move(innerCallback));
311         bool isSuccess = (handle != nullptr);
312         if (isSuccess) {
313             AddDownloadTaskForPreload(url, handle);
314         }
315         LOGI("Async http download src [%{private}s] [%{public}s]", url.c_str(),
316             isSuccess ? " successfully" : " failed to download, please check netStack log");
317         return isSuccess;
318     }
319 
fetchCachedResult(const std::string & url,std::string & result)320     bool fetchCachedResult(const std::string& url, std::string& result) override
321     {
322         auto data = Request::Preload::GetInstance()->fetch(url);
323         if (data.has_value()) {
324             result = std::string(data->bytes().data(), data->bytes().data() + data->bytes().length());
325             return true;
326         }
327         return false;
328     }
329 
DownloadSyncWithPreload(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId)330     bool DownloadSyncWithPreload(
331         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId) override
332     {
333         auto innerCallback = std::make_unique<Request::PreloadCallback>();
334         auto downloadCondition = std::make_shared<DownloadCondition>();
335         innerCallback->OnSuccess = [this, downloadCondition, url](
336                                        const std::shared_ptr<Request::Data>&& data, const std::string& taskId) {
337             LOGI("Sync http task of url [%{private}s-%{public}s] success", url.c_str(), taskId.c_str());
338             {
339                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
340                 downloadCondition->downloadSuccess = true;
341                 downloadCondition->dataOut =
342                     std::string(data->bytes().data(), data->bytes().data() + data->bytes().length());
343             }
344             downloadCondition->cv.notify_all();
345             RemoveDownloadTaskWithPreload(url, false);
346         };
347         innerCallback->OnCancel = [this, downloadCondition, url]() {
348             LOGI("Sync Http task of url [%{private}s] cancelled", url.c_str());
349             {
350                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
351                 downloadCondition->errorMsg.append("Http task of url ");
352                 downloadCondition->errorMsg.append(url.c_str());
353                 downloadCondition->errorMsg.append(" cancelled by netStack");
354                 downloadCondition->errorInfo = { ImageErrorCode::GET_IMAGE_SYNC_HTTP_CANCELLED,
355                     "sync http task of uri cancelled." };
356                 downloadCondition->downloadSuccess = false;
357             }
358             downloadCondition->cv.notify_all();
359             RemoveDownloadTaskWithPreload(url, false);
360         };
361         innerCallback->OnFail = [this, downloadCondition, url](
362                                     const Request::PreloadError& error, const std::string& taskId) {
363             LOGI("Sync http task of url [%{private}s-%{public}s] failed, reason [%{private}s]", url.c_str(),
364                 taskId.c_str(), error.GetMessage().c_str());
365             {
366                 std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
367                 std::string errorMsg = "Http task of url " + url + " failed, response code " +
368                                        std::to_string(error.GetCode()) + ", msg from netStack: " + error.GetMessage();
369                 downloadCondition->errorMsg = errorMsg;
370                 downloadCondition->errorInfo = { ImageErrorCode::GET_IMAGE_SYNC_HTTP_FAILED,
371                     "sync http task of uri failed." };
372                 downloadCondition->downloadSuccess = false;
373             }
374             downloadCondition->cv.notify_all();
375             RemoveDownloadTaskWithPreload(url, false);
376         };
377 
378         if (downloadCallback.onProgressCallback) {
379             innerCallback->OnProgress = [onProgressCallback = downloadCallback.onProgressCallback, instanceId](
380                                             uint64_t dlNow, uint64_t dlTotal) {
381                 onProgressCallback(dlTotal, dlNow, true, instanceId);
382             };
383         }
384         auto handle = Request::Preload::GetInstance()->load(url, std::move(innerCallback));
385         bool isSuccess = (handle != nullptr);
386         if (isSuccess) {
387             AddDownloadTaskForPreload(url, handle);
388         }
389         return HandleDownloadResult(isSuccess, std::move(downloadCallback), downloadCondition, instanceId, url);
390     }
391 
OnFail(std::shared_ptr<DownloadCondition> downloadCondition,const NetStackRequest & request,const NetStackResponse & response,const NetStackError & error)392     static void OnFail(std::shared_ptr<DownloadCondition> downloadCondition, const NetStackRequest& request,
393         const NetStackResponse& response, const NetStackError& error)
394     {
395         LOGI("Sync Http task of url [%{private}s] failed, response code %{public}d, msg from netStack: [%{public}s]",
396             request.GetURL().c_str(), response.GetResponseCode(), error.GetErrorMessage().c_str());
397         {
398             std::unique_lock<std::mutex> taskLock(downloadCondition->downloadMutex);
399             downloadCondition->errorMsg.append("Http task of url ");
400             downloadCondition->errorMsg.append(request.GetURL());
401             downloadCondition->errorMsg.append(" failed, response code ");
402             auto responseCode = response.GetResponseCode();
403             downloadCondition->errorMsg.append(std::to_string(responseCode));
404             downloadCondition->errorMsg.append(", msg from netStack: ");
405             downloadCondition->errorMsg.append(error.GetErrorMessage());
406             downloadCondition->downloadSuccess = false;
407         }
408         downloadCondition->cv.notify_all();
409     }
410 
RemoveDownloadTask(const std::string & url,int32_t nodeId,bool isCancel=true)411     bool RemoveDownloadTask(const std::string& url, int32_t nodeId, bool isCancel = true) override
412     {
413         std::scoped_lock lock(httpTaskMutex_);
414         auto urlKey = url + std::to_string(nodeId);
415         auto iter = httpTaskMap_.find(urlKey);
416         if (iter != httpTaskMap_.end()) {
417             auto task = iter->second;
418             if (task->GetStatus() == NetStackTaskStatus::RUNNING && isCancel) {
419                 LOGI("AceImage RemoveDownloadTask, url:%{private}s", url.c_str());
420                 task->Cancel();
421             }
422             httpTaskMap_.erase(iter);
423             return true;
424         }
425         return false;
426     }
427 
RemoveDownloadTaskWithPreload(const std::string & url,bool isCancel=true)428     bool RemoveDownloadTaskWithPreload(const std::string& url, bool isCancel = true) override
429     {
430         std::scoped_lock lock(httpHandleMutexForPreload_);
431         auto iter = httpHandleMapForPreload_.find(url);
432         if (iter != httpHandleMapForPreload_.end()) {
433             auto task = iter->second;
434             if (task->GetState() == Request::PreloadState::RUNNING && isCancel) {
435                 LOGI("AceImage RemoveDownloadHandle, url:%{private}s", url.c_str());
436                 task->Cancel();
437             }
438             httpHandleMapForPreload_.erase(iter);
439             return true;
440         }
441         return false;
442     }
443 
444 private:
445     struct ProxyInfo {
446         std::string host;
447         int32_t port = 0;
448         std::string exclusions;
449     };
450     std::mutex httpTaskMutex_;
451     std::unordered_map<std::string, std::shared_ptr<NetStackTask>> httpTaskMap_;
452     // use preload module to download the url
453     std::mutex httpHandleMutexForPreload_;
454     std::unordered_map<std::string, std::shared_ptr<Request::PreloadHandle>> httpHandleMapForPreload_;
455 
HandleDownloadResult(bool result,DownloadCallback && downloadCallback,const std::shared_ptr<DownloadCondition> & downloadCondition,int32_t instanceId,const std::string & url)456     bool HandleDownloadResult(bool result, DownloadCallback&& downloadCallback,
457         const std::shared_ptr<DownloadCondition>& downloadCondition, int32_t instanceId, const std::string& url)
458     {
459         if (!result) {
460             return result;
461         }
462         {
463             std::unique_lock<std::mutex> downloadLock(downloadCondition->downloadMutex);
464             // condition_variable is waiting for any of the success, cancel or failed to respond in sync mode
465             downloadCondition->cv.wait_for(
466                 downloadLock, std::chrono::milliseconds(MAXIMUM_WAITING_PERIOD), [downloadCondition] {
467                     return downloadCondition ? downloadCondition->downloadSuccess.has_value() : false;
468                 });
469         }
470         if (!downloadCondition->downloadSuccess.has_value()) {
471             LOGI("Sync Task of netstack with url [%{private}s] maximum waiting period exceed", url.c_str());
472         }
473         if (downloadCondition->downloadSuccess.value_or(false)) {
474             downloadCallback.successCallback(std::move(downloadCondition->dataOut), false, instanceId);
475         } else {
476             downloadCallback.failCallback(downloadCondition->errorMsg, downloadCondition->errorInfo, false, instanceId);
477         }
478         return true;
479     }
480 
HandleDownloadResult(bool result,const std::shared_ptr<DownloadCondition> & downloadCondition,const std::shared_ptr<DownloadResult> & downloadResult)481     bool HandleDownloadResult(bool result, const std::shared_ptr<DownloadCondition>& downloadCondition,
482         const std::shared_ptr<DownloadResult>& downloadResult)
483     {
484         if (!result) {
485             return result;
486         }
487         {
488             std::unique_lock<std::mutex> downloadLock(downloadCondition->downloadMutex);
489             // condition_variable is waiting for any of the success, cancel or failed to respond in sync mode
490             downloadCondition->cv.wait_for(
491                 downloadLock, std::chrono::milliseconds(MAXIMUM_WAITING_PERIOD), [downloadCondition, downloadResult] {
492                     return downloadCondition ? downloadResult->downloadSuccess.has_value() : false;
493                 });
494         }
495         return true;
496     }
497 
IsContains(const std::string & url)498     bool IsContains(const std::string& url) override
499     {
500         return Request::Preload::GetInstance()->Contains(url);
501     }
502 
AddDownloadTask(const std::string & url,const std::shared_ptr<NetStackTask> & task,int32_t nodeId)503     void AddDownloadTask(const std::string& url, const std::shared_ptr<NetStackTask>& task, int32_t nodeId)
504     {
505         std::scoped_lock lock(httpTaskMutex_);
506         httpTaskMap_.emplace(url + std::to_string(nodeId), task);
507     }
508 
509     // use preload module to download the url
AddDownloadTaskForPreload(const std::string & url,const std::shared_ptr<Request::PreloadHandle> & handle)510     void AddDownloadTaskForPreload(
511         const std::string& url, const std::shared_ptr<Request::PreloadHandle>& handle)
512     {
513         std::scoped_lock lock(httpHandleMutexForPreload_);
514         httpHandleMapForPreload_.emplace(url, handle);
515     }
516 
Initialize()517     bool Initialize()
518     {
519         if (initialized_) {
520             return true;
521         }
522 
523         std::lock_guard<std::mutex> lock(mutex_);
524         if (initialized_) {
525             return true;
526         }
527         if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
528             LOGE("Failed to initialize 'curl'");
529             return false;
530         }
531         initialized_ = true;
532         return true;
533     }
534 
OnWritingMemory(void * data,size_t size,size_t memBytes,void * userData)535     static size_t OnWritingMemory(void* data, size_t size, size_t memBytes, void* userData)
536     {
537         // size is always 1, for more details see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
538         auto& dataOut = *static_cast<std::vector<uint8_t>*>(userData);
539         auto chunkData = static_cast<uint8_t*>(data);
540         dataOut.insert(dataOut.end(), chunkData, chunkData + memBytes);
541         return memBytes;
542     }
543 
GetProxy(ProxyInfo & proxy)544     static bool GetProxy(ProxyInfo& proxy)
545     {
546         NetManagerStandard::HttpProxy httpProxy;
547         NetManagerStandard::NetConnClient::GetInstance().GetDefaultHttpProxy(httpProxy);
548         proxy.host = httpProxy.GetHost();
549         proxy.port = httpProxy.GetPort();
550 
551         auto exclusionList = httpProxy.GetExclusionList();
552         for (auto&& ex : exclusionList) {
553             proxy.exclusions.append(ex);
554             if (ex != exclusionList.back()) {
555                 proxy.exclusions.append(",");
556             }
557         }
558         return true;
559     }
560 
561     std::mutex mutex_;
562     bool initialized_ = false;
563     bool isCurl_ = false;
564 };
565 
OHOS_ACE_CreateDownloadManager()566 extern "C" ACE_FORCE_EXPORT void* OHOS_ACE_CreateDownloadManager()
567 {
568     return new DownloadManagerImpl();
569 }
570 } // namespace OHOS::Ace
571