123b3eb3cSopenharmony_ci/* 223b3eb3cSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 323b3eb3cSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 423b3eb3cSopenharmony_ci * you may not use this file except in compliance with the License. 523b3eb3cSopenharmony_ci * You may obtain a copy of the License at 623b3eb3cSopenharmony_ci * 723b3eb3cSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 823b3eb3cSopenharmony_ci * 923b3eb3cSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1023b3eb3cSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1123b3eb3cSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1223b3eb3cSopenharmony_ci * See the License for the specific language governing permissions and 1323b3eb3cSopenharmony_ci * limitations under the License. 1423b3eb3cSopenharmony_ci */ 1523b3eb3cSopenharmony_ci 1623b3eb3cSopenharmony_ci#include <condition_variable> 1723b3eb3cSopenharmony_ci#include <cstdint> 1823b3eb3cSopenharmony_ci#include <functional> 1923b3eb3cSopenharmony_ci#include <memory> 2023b3eb3cSopenharmony_ci#include <mutex> 2123b3eb3cSopenharmony_ci#include <optional> 2223b3eb3cSopenharmony_ci#include <string> 2323b3eb3cSopenharmony_ci#include <vector> 2423b3eb3cSopenharmony_ci 2523b3eb3cSopenharmony_ci#include "curl/curl.h" 2623b3eb3cSopenharmony_ci 2723b3eb3cSopenharmony_ci#include "base/log/log.h" 2823b3eb3cSopenharmony_ci#include "base/network/download_manager.h" 2923b3eb3cSopenharmony_ci#include "base/utils/macros.h" 3023b3eb3cSopenharmony_ci 3123b3eb3cSopenharmony_ci#define ACE_CURL_EASY_SET_OPTION(handle, opt, data) \ 3223b3eb3cSopenharmony_ci do { \ 3323b3eb3cSopenharmony_ci CURLcode result = curl_easy_setopt(handle, opt, data); \ 3423b3eb3cSopenharmony_ci if (result != CURLE_OK) { \ 3523b3eb3cSopenharmony_ci return false; \ 3623b3eb3cSopenharmony_ci } \ 3723b3eb3cSopenharmony_ci } while (0) 3823b3eb3cSopenharmony_ci 3923b3eb3cSopenharmony_cinamespace OHOS::Ace { 4023b3eb3cSopenharmony_ci 4123b3eb3cSopenharmony_cistd::unique_ptr<DownloadManager> DownloadManager::instance_ = nullptr; 4223b3eb3cSopenharmony_ci 4323b3eb3cSopenharmony_ciclass ACE_FORCE_EXPORT DownloadManagerPrview : public DownloadManager { 4423b3eb3cSopenharmony_cipublic: 4523b3eb3cSopenharmony_ci DownloadManagerPrview() = default; 4623b3eb3cSopenharmony_ci ~DownloadManagerPrview() 4723b3eb3cSopenharmony_ci { 4823b3eb3cSopenharmony_ci if (isCurl_) { 4923b3eb3cSopenharmony_ci curl_global_cleanup(); 5023b3eb3cSopenharmony_ci } 5123b3eb3cSopenharmony_ci } 5223b3eb3cSopenharmony_ci 5323b3eb3cSopenharmony_ci bool Download(const std::string& url, std::vector<uint8_t>& dataOut) override 5423b3eb3cSopenharmony_ci { 5523b3eb3cSopenharmony_ci // when calling, it is necessary to set it to true and call curl clean up method 5623b3eb3cSopenharmony_ci // during download manager ohos object destruction 5723b3eb3cSopenharmony_ci isCurl_ = true; 5823b3eb3cSopenharmony_ci if (!Initialize()) { 5923b3eb3cSopenharmony_ci return false; 6023b3eb3cSopenharmony_ci } 6123b3eb3cSopenharmony_ci 6223b3eb3cSopenharmony_ci std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle(curl_easy_init(), &curl_easy_cleanup); 6323b3eb3cSopenharmony_ci if (!handle) { 6423b3eb3cSopenharmony_ci return false; 6523b3eb3cSopenharmony_ci } 6623b3eb3cSopenharmony_ci 6723b3eb3cSopenharmony_ci dataOut.clear(); 6823b3eb3cSopenharmony_ci std::string errorStr; 6923b3eb3cSopenharmony_ci errorStr.reserve(CURL_ERROR_SIZE); 7023b3eb3cSopenharmony_ci 7123b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str()); 7223b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEFUNCTION, OnWritingMemory); 7323b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEDATA, &dataOut); 7423b3eb3cSopenharmony_ci // Some servers don't like requests that are made without a user-agent field, so we provide one 7523b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_USERAGENT, "libcurl-agent/1.0"); 7623b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_URL, url.c_str()); 7723b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_VERBOSE, 1L); 7823b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_ERRORBUFFER, errorStr.data()); 7923b3eb3cSopenharmony_ci 8023b3eb3cSopenharmony_ci ProxyInfo proxy; 8123b3eb3cSopenharmony_ci if (GetProxy(proxy)) { 8223b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXY, proxy.host.c_str()); 8323b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXYPORT, proxy.port); 8423b3eb3cSopenharmony_ci if (!proxy.exclusions.empty()) { 8523b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_NOPROXY, proxy.exclusions.c_str()); 8623b3eb3cSopenharmony_ci } 8723b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_PROXYTYPE, CURLPROXY_HTTP); 8823b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_HTTPPROXYTUNNEL, 1L); 8923b3eb3cSopenharmony_ci } 9023b3eb3cSopenharmony_ci 9123b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYPEER, 0L); 9223b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_SSL_VERIFYHOST, 0L); 9323b3eb3cSopenharmony_ci 9423b3eb3cSopenharmony_ci CURLcode result = curl_easy_perform(handle.get()); 9523b3eb3cSopenharmony_ci if (result != CURLE_OK) { 9623b3eb3cSopenharmony_ci LOGE("Failed to download, url: %{private}s, %{public}s", url.c_str(), curl_easy_strerror(result)); 9723b3eb3cSopenharmony_ci if (!errorStr.empty()) { 9823b3eb3cSopenharmony_ci LOGE("Failed to download reason: %{public}s", errorStr.c_str()); 9923b3eb3cSopenharmony_ci } 10023b3eb3cSopenharmony_ci dataOut.clear(); 10123b3eb3cSopenharmony_ci return false; 10223b3eb3cSopenharmony_ci } 10323b3eb3cSopenharmony_ci dataOut.shrink_to_fit(); 10423b3eb3cSopenharmony_ci return true; 10523b3eb3cSopenharmony_ci } 10623b3eb3cSopenharmony_ci 10723b3eb3cSopenharmony_ci bool Download(const std::string& url, const std::shared_ptr<DownloadResult>& result) override 10823b3eb3cSopenharmony_ci { 10923b3eb3cSopenharmony_ci return false; 11023b3eb3cSopenharmony_ci } 11123b3eb3cSopenharmony_ci 11223b3eb3cSopenharmony_ci bool DownloadAsync( 11323b3eb3cSopenharmony_ci DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override 11423b3eb3cSopenharmony_ci { 11523b3eb3cSopenharmony_ci return false; 11623b3eb3cSopenharmony_ci } 11723b3eb3cSopenharmony_ci 11823b3eb3cSopenharmony_ci bool DownloadSync( 11923b3eb3cSopenharmony_ci DownloadCallback&& downloadCallback, const std::string& url, int32_t instanceId, int32_t nodeId) override 12023b3eb3cSopenharmony_ci { 12123b3eb3cSopenharmony_ci return false; 12223b3eb3cSopenharmony_ci } 12323b3eb3cSopenharmony_ci 12423b3eb3cSopenharmony_ci bool RemoveDownloadTask(const std::string& url, int32_t nodeId) override 12523b3eb3cSopenharmony_ci { 12623b3eb3cSopenharmony_ci return false; 12723b3eb3cSopenharmony_ci } 12823b3eb3cSopenharmony_ci 12923b3eb3cSopenharmony_ciprivate: 13023b3eb3cSopenharmony_ci struct ProxyInfo { 13123b3eb3cSopenharmony_ci std::string host; 13223b3eb3cSopenharmony_ci int32_t port = 0; 13323b3eb3cSopenharmony_ci std::string exclusions; 13423b3eb3cSopenharmony_ci }; 13523b3eb3cSopenharmony_ci 13623b3eb3cSopenharmony_ci bool Initialize() 13723b3eb3cSopenharmony_ci { 13823b3eb3cSopenharmony_ci if (initialized_) { 13923b3eb3cSopenharmony_ci return true; 14023b3eb3cSopenharmony_ci } 14123b3eb3cSopenharmony_ci 14223b3eb3cSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 14323b3eb3cSopenharmony_ci if (initialized_) { 14423b3eb3cSopenharmony_ci return true; 14523b3eb3cSopenharmony_ci } 14623b3eb3cSopenharmony_ci if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 14723b3eb3cSopenharmony_ci LOGE("Failed to initialize 'curl'"); 14823b3eb3cSopenharmony_ci return false; 14923b3eb3cSopenharmony_ci } 15023b3eb3cSopenharmony_ci initialized_ = true; 15123b3eb3cSopenharmony_ci return true; 15223b3eb3cSopenharmony_ci } 15323b3eb3cSopenharmony_ci 15423b3eb3cSopenharmony_ci static size_t OnWritingMemory(void* data, size_t size, size_t memBytes, void* userData) 15523b3eb3cSopenharmony_ci { 15623b3eb3cSopenharmony_ci // size is always 1, for more details see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html 15723b3eb3cSopenharmony_ci auto& dataOut = *static_cast<std::vector<uint8_t>*>(userData); 15823b3eb3cSopenharmony_ci auto chunkData = static_cast<uint8_t*>(data); 15923b3eb3cSopenharmony_ci dataOut.insert(dataOut.end(), chunkData, chunkData + memBytes); 16023b3eb3cSopenharmony_ci return memBytes; 16123b3eb3cSopenharmony_ci } 16223b3eb3cSopenharmony_ci 16323b3eb3cSopenharmony_ci static bool GetProxy(ProxyInfo& proxy) 16423b3eb3cSopenharmony_ci { 16523b3eb3cSopenharmony_ci return false; 16623b3eb3cSopenharmony_ci } 16723b3eb3cSopenharmony_ci 16823b3eb3cSopenharmony_ci std::mutex mutex_; 16923b3eb3cSopenharmony_ci bool initialized_ = false; 17023b3eb3cSopenharmony_ci bool isCurl_ = false; 17123b3eb3cSopenharmony_ci}; 17223b3eb3cSopenharmony_ci 17323b3eb3cSopenharmony_ciDownloadManager* DownloadManager::GetInstance() 17423b3eb3cSopenharmony_ci{ 17523b3eb3cSopenharmony_ci static std::once_flag onceFlag; 17623b3eb3cSopenharmony_ci std::call_once(onceFlag, []() { 17723b3eb3cSopenharmony_ci instance_.reset(new DownloadManagerPrview()); 17823b3eb3cSopenharmony_ci }); 17923b3eb3cSopenharmony_ci return instance_.get(); 18023b3eb3cSopenharmony_ci} 18123b3eb3cSopenharmony_ci} // namespace OHOS::Ace 182