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