• 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 <condition_variable>
17 #include <cstdint>
18 #include <functional>
19 #include <memory>
20 #include <mutex>
21 #include <optional>
22 #include <string>
23 #include <vector>
24 
25 #include "curl/curl.h"
26 
27 #include "base/log/log.h"
28 #include "base/network/download_manager.h"
29 #include "base/utils/macros.h"
30 
31 #define ACE_CURL_EASY_SET_OPTION(handle, opt, data)            \
32     do {                                                       \
33         CURLcode result = curl_easy_setopt(handle, opt, data); \
34         if (result != CURLE_OK) {                              \
35             return false;                                      \
36         }                                                      \
37     } while (0)
38 
39 namespace OHOS::Ace {
40 
41 std::unique_ptr<DownloadManager> DownloadManager::instance_ = nullptr;
42 
43 class ACE_FORCE_EXPORT DownloadManagerPrview : public DownloadManager {
44 public:
45     DownloadManagerPrview() = default;
~DownloadManagerPrview()46     ~DownloadManagerPrview()
47     {
48         if (isCurl_) {
49             curl_global_cleanup();
50         }
51     }
52 
Download(const std::string & url,std::vector<uint8_t> & dataOut)53     bool Download(const std::string& url, std::vector<uint8_t>& dataOut) override
54     {
55         // when calling, it is necessary to set it to true and call curl clean up method
56         // during download manager ohos object destruction
57         isCurl_ = true;
58         if (!Initialize()) {
59             return false;
60         }
61 
62         std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle(curl_easy_init(), &curl_easy_cleanup);
63         if (!handle) {
64             return false;
65         }
66 
67         dataOut.clear();
68         std::string errorStr;
69         errorStr.reserve(CURL_ERROR_SIZE);
70 
71         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str());
72         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEFUNCTION, OnWritingMemory);
73         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEDATA, &dataOut);
74         // Some servers don't like requests that are made without a user-agent field, so we provide one
75         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_USERAGENT, "libcurl-agent/1.0");
76         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str());
77         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_VERBOSE, 1L);
78         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_ERRORBUFFER, errorStr.data());
79 
80         ProxyInfo proxy;
81         if (GetProxy(proxy)) {
82             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXY, proxy.host.c_str());
83             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXYPORT, proxy.port);
84             if (!proxy.exclusions.empty()) {
85                 ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_NOPROXY, proxy.exclusions.c_str());
86             }
87             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
88             ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_HTTPPROXYTUNNEL, 1L);
89         }
90 
91         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYPEER, 0L);
92         ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYHOST, 0L);
93 
94         CURLcode result = curl_easy_perform(handle.get());
95         if (result != CURLE_OK) {
96             LOGE("Failed to download, url: %{private}s, %{public}s", url.c_str(), curl_easy_strerror(result));
97             if (!errorStr.empty()) {
98                 LOGE("Failed to download reason: %{public}s", errorStr.c_str());
99             }
100             dataOut.clear();
101             return false;
102         }
103         dataOut.shrink_to_fit();
104         return true;
105     }
106 
Download(const std::string & url,const std::shared_ptr<DownloadResult> & result)107     bool Download(const std::string& url, const std::shared_ptr<DownloadResult>& result) override
108     {
109         return false;
110     }
111 
DownloadAsync(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId,int32_t nodeId)112     bool DownloadAsync(
113         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override
114     {
115         return false;
116     }
117 
DownloadSync(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId,int32_t nodeId)118     bool DownloadSync(
119         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override
120     {
121         return false;
122     }
123 
DownloadAsyncWithPreload(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId)124     bool DownloadAsyncWithPreload(
125         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId) override
126     {
127         return false;
128     }
129 
DownloadSyncWithPreload(DownloadCallback && downloadCallback,const std::string & url,int32_t instanceId)130     bool DownloadSyncWithPreload(
131         DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId) override
132     {
133         return false;
134     }
135 
fetchCachedResult(const std::string & url,std::string & result)136     bool fetchCachedResult(const std::string& url, std::string& result) override
137     {
138         return false;
139     }
140 
RemoveDownloadTask(const std::string & url,int32_t nodeId,bool isCancel=true)141     bool RemoveDownloadTask(const std::string& url, int32_t nodeId, bool isCancel = true) override
142     {
143         return false;
144     }
145 
RemoveDownloadTaskWithPreload(const std::string & url,bool isCancel=true)146     bool RemoveDownloadTaskWithPreload(const std::string& url, bool isCancel = true) override
147     {
148         return false;
149     }
150 
IsContains(const std::string & url)151     bool IsContains(const std::string& url) override
152     {
153         return false;
154     }
155 
156 private:
157     struct ProxyInfo {
158         std::string host;
159         int32_t port = 0;
160         std::string exclusions;
161     };
162 
Initialize()163     bool Initialize()
164     {
165         if (initialized_) {
166             return true;
167         }
168 
169         std::lock_guard<std::mutex> lock(mutex_);
170         if (initialized_) {
171             return true;
172         }
173         if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
174             LOGE("Failed to initialize 'curl'");
175             return false;
176         }
177         initialized_ = true;
178         return true;
179     }
180 
OnWritingMemory(void * data,size_t size,size_t memBytes,void * userData)181     static size_t OnWritingMemory(void* data, size_t size, size_t memBytes, void* userData)
182     {
183         // size is always 1, for more details see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
184         auto& dataOut = *static_cast<std::vector<uint8_t>*>(userData);
185         auto chunkData = static_cast<uint8_t*>(data);
186         dataOut.insert(dataOut.end(), chunkData, chunkData + memBytes);
187         return memBytes;
188     }
189 
GetProxy(ProxyInfo & proxy)190     static bool GetProxy(ProxyInfo& proxy)
191     {
192         return false;
193     }
194 
195     std::mutex mutex_;
196     bool initialized_ = false;
197     bool isCurl_ = false;
198 };
199 
GetInstance()200 DownloadManager* DownloadManager::GetInstance()
201 {
202     static std::once_flag onceFlag;
203     std::call_once(onceFlag, []() {
204         instance_.reset(new DownloadManagerPrview());
205     });
206     return instance_.get();
207 }
208 } // namespace OHOS::Ace
209