• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "base/network/download_manager.h"
17 
18 #include <memory>
19 #include <mutex>
20 
21 #include "curl/curl.h"
22 
23 #include "base/log/log.h"
24 #include "base/utils/singleton.h"
25 #include "base/utils/utils.h"
26 
27 #define ACE_CURL_EASY_SET_OPTION(handle, opt, data) \
28     do { \
29         CURLcode result = curl_easy_setopt(handle, opt, data); \
30         if (result != CURLE_OK) { \
31             LOGE("Failed to set option: %{public}s, %{public}s", #opt, curl_easy_strerror(result)); \
32             return false; \
33         } \
34     } while (0)
35 
36 namespace OHOS::Ace {
37 namespace {
38 
39 class DownloadManagerImpl final : public DownloadManager, public Singleton<DownloadManagerImpl> {
40     DECLARE_SINGLETON(DownloadManagerImpl);
41     ACE_DISALLOW_MOVE(DownloadManagerImpl);
42 
43 public:
Download(const std::string & url,std::vector<uint8_t> & dataOut)44     bool Download(const std::string& url, std::vector<uint8_t>& dataOut) override
45     {
46         if (!Initialize()) {
47             return false;
48         }
49 
50         std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle(curl_easy_init(), &curl_easy_cleanup);
51         if (!handle) {
52             LOGE("Failed to create download task");
53             return false;
54         }
55 
56         dataOut.clear();
57         std::string errorStr;
58         errorStr.reserve(CURL_ERROR_SIZE);
59 
60         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str());
61         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEFUNCTION, OnWritingMemory);
62         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEDATA, &dataOut);
63         // Some servers don't like requests that are made without a user-agent field, so we provide one
64         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_USERAGENT, "libcurl-agent/1.0");
65         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str());
66 #if !defined(PREVIEW)
67         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_CAINFO, "/etc/ssl/certs/cacert.pem");
68 #endif
69         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_VERBOSE, 1L);
70         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_ERRORBUFFER, errorStr.data());
71 
72 #ifdef IOS_PLATFORM
73         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYPEER, 0L);
74         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYHOST, 0L);
75 #endif
76 
77         CURLcode result = curl_easy_perform(handle.get());
78         if (result != CURLE_OK) {
79             LOGE("Failed to download, url: %{private}s, %{public}s", url.c_str(), curl_easy_strerror(result));
80             if (!errorStr.empty()) {
81                 LOGE("Failed to download reason: %{public}s", errorStr.c_str());
82             }
83             dataOut.clear();
84             return false;
85         }
86         dataOut.shrink_to_fit();
87         return true;
88     }
89 
90 private:
OnWritingMemory(void * data,size_t size,size_t memBytes,void * userData)91     static size_t OnWritingMemory(void* data, size_t size, size_t memBytes, void* userData)
92     {
93         // size is always 1, for more details see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
94         auto& dataOut = *static_cast<std::vector<uint8_t>*>(userData);
95         auto chunkData = static_cast<uint8_t*>(data);
96         dataOut.insert(dataOut.end(), chunkData, chunkData + memBytes);
97         return memBytes;
98     }
99 
Initialize()100     bool Initialize()
101     {
102         if (initialized_) {
103             return true;
104         }
105 
106         std::lock_guard<std::mutex> lock(mutex_);
107         if (initialized_) {
108             return true;
109         }
110         if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
111             LOGE("Failed to initialize 'curl'");
112             return false;
113         }
114         initialized_ = true;
115         return true;
116     }
117 
118     std::mutex mutex_;
119     bool initialized_ = false;
120 };
121 
122 DownloadManagerImpl::DownloadManagerImpl() = default;
123 
~DownloadManagerImpl()124 DownloadManagerImpl::~DownloadManagerImpl()
125 {
126     curl_global_cleanup();
127 }
128 
129 }
130 
GetInstance()131 DownloadManager& DownloadManager::GetInstance()
132 {
133     return Singleton<DownloadManagerImpl>::GetInstance();
134 }
135 
136 } // namespace OHOS::Ace
137