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