123b3eb3cSopenharmony_ci/* 223b3eb3cSopenharmony_ci * Copyright (c) 2021 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 "adapter/preview/osal/fetch_manager.h" 1723b3eb3cSopenharmony_ci 1823b3eb3cSopenharmony_ci#include <memory> 1923b3eb3cSopenharmony_ci#include <mutex> 2023b3eb3cSopenharmony_ci 2123b3eb3cSopenharmony_ci#include "curl/curl.h" 2223b3eb3cSopenharmony_ci 2323b3eb3cSopenharmony_ci#include "adapter/preview/osal/http_constant.h" 2423b3eb3cSopenharmony_ci#include "base/log/log.h" 2523b3eb3cSopenharmony_ci#include "base/utils/singleton.h" 2623b3eb3cSopenharmony_ci 2723b3eb3cSopenharmony_ci#define ACE_CURL_EASY_SET_OPTION(handle, opt, data) \ 2823b3eb3cSopenharmony_ci do { \ 2923b3eb3cSopenharmony_ci CURLcode result = curl_easy_setopt(handle, opt, data); \ 3023b3eb3cSopenharmony_ci if (result != CURLE_OK) { \ 3123b3eb3cSopenharmony_ci LOGW("Failed to set option: %{public}s, %{public}s", #opt, curl_easy_strerror(result)); \ 3223b3eb3cSopenharmony_ci return false; \ 3323b3eb3cSopenharmony_ci } \ 3423b3eb3cSopenharmony_ci } while (0) 3523b3eb3cSopenharmony_ci 3623b3eb3cSopenharmony_cinamespace OHOS::Ace { 3723b3eb3cSopenharmony_cinamespace { 3823b3eb3cSopenharmony_ci 3923b3eb3cSopenharmony_ciclass FetchManagerImpl final : public FetchManager, public Singleton<FetchManagerImpl> { 4023b3eb3cSopenharmony_ci DECLARE_SINGLETON(FetchManagerImpl); 4123b3eb3cSopenharmony_ci ACE_DISALLOW_MOVE(FetchManagerImpl); 4223b3eb3cSopenharmony_ci 4323b3eb3cSopenharmony_cipublic: 4423b3eb3cSopenharmony_ci bool Fetch(const RequestData requestData, const int32_t callbackId, ResponseData& responseData) override 4523b3eb3cSopenharmony_ci { 4623b3eb3cSopenharmony_ci if (!Initialize()) { 4723b3eb3cSopenharmony_ci return false; 4823b3eb3cSopenharmony_ci } 4923b3eb3cSopenharmony_ci 5023b3eb3cSopenharmony_ci std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle(curl_easy_init(), &curl_easy_cleanup); 5123b3eb3cSopenharmony_ci if (!handle) { 5223b3eb3cSopenharmony_ci return false; 5323b3eb3cSopenharmony_ci } 5423b3eb3cSopenharmony_ci 5523b3eb3cSopenharmony_ci struct curl_slist* header = nullptr; 5623b3eb3cSopenharmony_ci if (!requestData.GetHeader().empty()) { 5723b3eb3cSopenharmony_ci for (auto&& [key, value] : requestData.GetHeader()) { 5823b3eb3cSopenharmony_ci header = curl_slist_append(header, (key + ":" + value).c_str()); 5923b3eb3cSopenharmony_ci } 6023b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_HTTPHEADER, header); 6123b3eb3cSopenharmony_ci } 6223b3eb3cSopenharmony_ci 6323b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_TIMEOUT_MS, HttpConstant::TIME_OUT); 6423b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_CONNECTTIMEOUT_MS, HttpConstant::TIME_OUT); 6523b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_BUFFERSIZE, HttpConstant::BUFFER_SIZE); 6623b3eb3cSopenharmony_ci 6723b3eb3cSopenharmony_ci std::string responseBody; 6823b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEFUNCTION, OnWritingMemoryBody); 6923b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_WRITEDATA, &responseBody); 7023b3eb3cSopenharmony_ci 7123b3eb3cSopenharmony_ci std::string responseHeader; 7223b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_HEADERFUNCTION, OnWritingMemoryHeader); 7323b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_HEADERDATA, &responseHeader); 7423b3eb3cSopenharmony_ci 7523b3eb3cSopenharmony_ci // Some servers don't like requests that are made without a user-agent field, so we provide one 7623b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(handle.get(), CURLOPT_USERAGENT, "libcurl-agent/1.0"); 7723b3eb3cSopenharmony_ci 7823b3eb3cSopenharmony_ci std::string method = requestData.GetMethod(); 7923b3eb3cSopenharmony_ci if (method.empty()) { 8023b3eb3cSopenharmony_ci method = "GET"; 8123b3eb3cSopenharmony_ci } 8223b3eb3cSopenharmony_ci if (method == HttpConstant::HTTP_METHOD_HEAD || method == HttpConstant::HTTP_METHOD_OPTIONS || 8323b3eb3cSopenharmony_ci method == HttpConstant::HTTP_METHOD_DELETE || method == HttpConstant::HTTP_METHOD_TRACE || 8423b3eb3cSopenharmony_ci method == HttpConstant::HTTP_METHOD_GET) { 8523b3eb3cSopenharmony_ci SetOptionForGet(requestData, handle.get()); 8623b3eb3cSopenharmony_ci } else if (method == HttpConstant::HTTP_METHOD_POST || method == HttpConstant::HTTP_METHOD_PUT) { 8723b3eb3cSopenharmony_ci SetOptionForPost(requestData, handle.get()); 8823b3eb3cSopenharmony_ci } else { 8923b3eb3cSopenharmony_ci responseData.SetCode(HttpConstant::ERROR); 9023b3eb3cSopenharmony_ci responseData.SetData(responseBody); 9123b3eb3cSopenharmony_ci return true; 9223b3eb3cSopenharmony_ci } 9323b3eb3cSopenharmony_ci 9423b3eb3cSopenharmony_ci CURLcode result = curl_easy_perform(handle.get()); 9523b3eb3cSopenharmony_ci if (result != CURLE_OK) { 9623b3eb3cSopenharmony_ci LOGW("Failed to fetch, url: %{private}s, %{public}s", requestData.GetUrl().c_str(), 9723b3eb3cSopenharmony_ci curl_easy_strerror(result)); 9823b3eb3cSopenharmony_ci responseData.SetCode(HttpConstant::ERROR); 9923b3eb3cSopenharmony_ci responseData.SetData(responseBody); 10023b3eb3cSopenharmony_ci return true; 10123b3eb3cSopenharmony_ci } 10223b3eb3cSopenharmony_ci 10323b3eb3cSopenharmony_ci char* ct = nullptr; 10423b3eb3cSopenharmony_ci curl_easy_getinfo(handle.get(), CURLINFO_CONTENT_TYPE, &ct); 10523b3eb3cSopenharmony_ci 10623b3eb3cSopenharmony_ci int32_t responseCode = HttpConstant::ERROR; 10723b3eb3cSopenharmony_ci curl_easy_getinfo(handle.get(), CURLINFO_RESPONSE_CODE, &responseCode); 10823b3eb3cSopenharmony_ci responseData.SetCode(responseCode); 10923b3eb3cSopenharmony_ci responseData.SetData(responseBody); 11023b3eb3cSopenharmony_ci responseData.SetHeaders(responseHeader); 11123b3eb3cSopenharmony_ci if (header != nullptr) { 11223b3eb3cSopenharmony_ci curl_slist_free_all(header); 11323b3eb3cSopenharmony_ci } 11423b3eb3cSopenharmony_ci return true; 11523b3eb3cSopenharmony_ci } 11623b3eb3cSopenharmony_ci 11723b3eb3cSopenharmony_ci bool SetOptionForGet(const RequestData requestData, CURL* curl) const 11823b3eb3cSopenharmony_ci { 11923b3eb3cSopenharmony_ci // refer to function buildConnectionWithParam() in HttpFetchImpl.java 12023b3eb3cSopenharmony_ci std::string url = requestData.GetUrl(); 12123b3eb3cSopenharmony_ci if (requestData.GetData() != "") { 12223b3eb3cSopenharmony_ci std::size_t index = url.find(HttpConstant::URL_PARAM_SEPARATOR); 12323b3eb3cSopenharmony_ci if (index != std::string::npos) { 12423b3eb3cSopenharmony_ci std::string param = url.substr(index + 1); 12523b3eb3cSopenharmony_ci 12623b3eb3cSopenharmony_ci std::string encodeIn = param + HttpConstant::URL_PARAM_DELIMITER + requestData.GetData(); 12723b3eb3cSopenharmony_ci char* encodeOut = curl_easy_escape(curl, encodeIn.c_str(), 0); 12823b3eb3cSopenharmony_ci if (encodeOut != nullptr) { 12923b3eb3cSopenharmony_ci url = url.substr(0, index + 1) + encodeOut; 13023b3eb3cSopenharmony_ci curl_free(encodeOut); 13123b3eb3cSopenharmony_ci } 13223b3eb3cSopenharmony_ci } else { 13323b3eb3cSopenharmony_ci char* encodeOut = curl_easy_escape(curl, requestData.GetData().c_str(), 0); 13423b3eb3cSopenharmony_ci if (encodeOut != nullptr) { 13523b3eb3cSopenharmony_ci url = url + HttpConstant::URL_PARAM_SEPARATOR + encodeOut; 13623b3eb3cSopenharmony_ci curl_free(encodeOut); 13723b3eb3cSopenharmony_ci } 13823b3eb3cSopenharmony_ci } 13923b3eb3cSopenharmony_ci } 14023b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, url.c_str()); 14123b3eb3cSopenharmony_ci return true; 14223b3eb3cSopenharmony_ci } 14323b3eb3cSopenharmony_ci 14423b3eb3cSopenharmony_ci bool SetOptionForPost(const RequestData requestData, CURL* curl) const 14523b3eb3cSopenharmony_ci { 14623b3eb3cSopenharmony_ci // refer to function buildConnectionWithStream() in HttpFetchImpl.java 14723b3eb3cSopenharmony_ci std::string url = requestData.GetUrl(); 14823b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, url.c_str()); 14923b3eb3cSopenharmony_ci ACE_CURL_EASY_SET_OPTION(curl, CURLOPT_POSTFIELDS, requestData.GetData().c_str()); 15023b3eb3cSopenharmony_ci return true; 15123b3eb3cSopenharmony_ci } 15223b3eb3cSopenharmony_ci 15323b3eb3cSopenharmony_ciprivate: 15423b3eb3cSopenharmony_ci static size_t OnWritingMemoryBody(const void* data, size_t size, size_t memBytes, void* userData) 15523b3eb3cSopenharmony_ci { 15623b3eb3cSopenharmony_ci ((std::string*)userData)->append((char*)data, 0, size * memBytes); 15723b3eb3cSopenharmony_ci return size * memBytes; 15823b3eb3cSopenharmony_ci } 15923b3eb3cSopenharmony_ci static size_t OnWritingMemoryHeader(const void* data, size_t size, size_t memBytes, void* userData) 16023b3eb3cSopenharmony_ci { 16123b3eb3cSopenharmony_ci ((std::string*)userData)->append((char*)data, 0, size * memBytes); 16223b3eb3cSopenharmony_ci return size * memBytes; 16323b3eb3cSopenharmony_ci } 16423b3eb3cSopenharmony_ci 16523b3eb3cSopenharmony_ci bool Initialize() 16623b3eb3cSopenharmony_ci { 16723b3eb3cSopenharmony_ci if (initialized_) { 16823b3eb3cSopenharmony_ci return true; 16923b3eb3cSopenharmony_ci } 17023b3eb3cSopenharmony_ci 17123b3eb3cSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 17223b3eb3cSopenharmony_ci if (initialized_) { 17323b3eb3cSopenharmony_ci return true; 17423b3eb3cSopenharmony_ci } 17523b3eb3cSopenharmony_ci if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 17623b3eb3cSopenharmony_ci LOGE("Failed to initialize 'curl'"); 17723b3eb3cSopenharmony_ci return false; 17823b3eb3cSopenharmony_ci } 17923b3eb3cSopenharmony_ci initialized_ = true; 18023b3eb3cSopenharmony_ci return true; 18123b3eb3cSopenharmony_ci } 18223b3eb3cSopenharmony_ci 18323b3eb3cSopenharmony_ci std::mutex mutex_; 18423b3eb3cSopenharmony_ci bool initialized_ = false; 18523b3eb3cSopenharmony_ci}; 18623b3eb3cSopenharmony_ci 18723b3eb3cSopenharmony_ciFetchManagerImpl::FetchManagerImpl() = default; 18823b3eb3cSopenharmony_ci 18923b3eb3cSopenharmony_ciFetchManagerImpl::~FetchManagerImpl() 19023b3eb3cSopenharmony_ci{ 19123b3eb3cSopenharmony_ci curl_global_cleanup(); 19223b3eb3cSopenharmony_ci} 19323b3eb3cSopenharmony_ci 19423b3eb3cSopenharmony_ci} // namespace 19523b3eb3cSopenharmony_ci 19623b3eb3cSopenharmony_ciFetchManager& FetchManager::GetInstance() 19723b3eb3cSopenharmony_ci{ 19823b3eb3cSopenharmony_ci return Singleton<FetchManagerImpl>::GetInstance(); 19923b3eb3cSopenharmony_ci} 20023b3eb3cSopenharmony_ci 20123b3eb3cSopenharmony_ci} // namespace OHOS::Ace 202