1 /*
2  * Copyright (c) 2021-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 "http_exec.h"
17 
18 #include <cstddef>
19 #include <cstring>
20 #include <memory>
21 #include <pthread.h>
22 #include <sstream>
23 #include <thread>
24 #include <unistd.h>
25 #ifdef HTTP_MULTIPATH_CERT_ENABLE
26 #include <openssl/ssl.h>
27 #endif
28 #if HAS_NETMANAGER_BASE
29 #include <netdb.h>
30 #endif
31 
32 #ifdef HTTP_PROXY_ENABLE
33 #include "parameter.h"
34 #endif
35 #ifdef HAS_NETMANAGER_BASE
36 #include "http_proxy.h"
37 #include "net_conn_client.h"
38 #include "netsys_client.h"
39 #endif
40 #include "base64_utils.h"
41 #include "cache_proxy.h"
42 #include "constant.h"
43 #if HAS_NETMANAGER_BASE
44 #include "epoll_request_handler.h"
45 #endif
46 #include "event_list.h"
47 #if HAS_NETMANAGER_BASE
48 #include "hitrace_meter.h"
49 #endif
50 #include "http_async_work.h"
51 #include "http_time.h"
52 #include "napi_utils.h"
53 #include "netstack_common_utils.h"
54 #include "netstack_log.h"
55 #include "secure_char.h"
56 #include "securec.h"
57 
58 #define NETSTACK_CURL_EASY_SET_OPTION(handle, opt, data, asyncContext)                                   \
59     do {                                                                                                 \
60         CURLcode result = curl_easy_setopt(handle, opt, data);                                           \
61         if (result != CURLE_OK) {                                                                        \
62             const char *err = curl_easy_strerror(result);                                                \
63             NETSTACK_LOGE("Failed to set option: %{public}s, %{public}s %{public}d", #opt, err, result); \
64             (asyncContext)->SetErrorCode(result);                                                        \
65             return false;                                                                                \
66         }                                                                                                \
67     } while (0)
68 
69 namespace OHOS::NetStack::Http {
70 #if !HAS_NETMANAGER_BASE
71 static constexpr int CURL_TIMEOUT_MS = 20;
72 static constexpr int CONDITION_TIMEOUT_S = 3600;
73 static constexpr int CURL_MAX_WAIT_MSECS = 10;
74 static constexpr int CURL_HANDLE_NUM = 10;
75 #endif
76 static constexpr const uint32_t EVENT_PARAM_ZERO = 0;
77 static constexpr const uint32_t EVENT_PARAM_ONE = 1;
78 static constexpr const uint32_t EVENT_PARAM_TWO = 2;
79 static constexpr const char *TLS12_SECURITY_CIPHER_SUITE = R"(DEFAULT:!eNULL:!EXPORT)";
80 #if !HAS_NETMANAGER_BASE
81 static constexpr const char *HTTP_TASK_RUN_THREAD = "OS_NET_TaskHttp";
82 static constexpr const char *HTTP_CLIENT_TASK_THREAD = "OS_NET_HttpJs";
83 #endif
84 
85 #if HAS_NETMANAGER_BASE
86 static constexpr const char *HTTP_REQ_TRACE_NAME = "HttpRequest";
87 #endif
88 #ifdef HTTP_MULTIPATH_CERT_ENABLE
89 static constexpr const int32_t UID_TRANSFORM_DIVISOR = 200000;
90 static constexpr const char *BASE_PATH = "/data/certificates/user_cacerts/";
91 static constexpr const char *USER_CERT_ROOT_PATH = "/data/certificates/user_cacerts/0/";
92 static constexpr int32_t SYSPARA_MAX_SIZE = 128;
93 static constexpr const char *DEFAULT_HTTP_PROXY_HOST = "NONE";
94 static constexpr const char *DEFAULT_HTTP_PROXY_PORT = "0";
95 static constexpr const char *DEFAULT_HTTP_PROXY_EXCLUSION_LIST = "NONE";
96 static constexpr const char *HTTP_PROXY_HOST_KEY = "persist.netmanager_base.http_proxy.host";
97 static constexpr const char *HTTP_PROXY_PORT_KEY = "persist.netmanager_base.http_proxy.port";
98 static constexpr const char *HTTP_PROXY_EXCLUSIONS_KEY = "persist.netmanager_base.http_proxy.exclusion_list";
99 #endif
100 
RequestContextDeleter(RequestContext * context)101 static void RequestContextDeleter(RequestContext *context)
102 {
103     context->DeleteReference();
104     delete context;
105     context = nullptr;
106 }
107 
AsyncWorkRequestInStreamCallback(napi_env env,napi_status status,void * data)108 static void AsyncWorkRequestInStreamCallback(napi_env env, napi_status status, void *data)
109 {
110     if (status != napi_ok) {
111         return;
112     }
113     std::unique_ptr<RequestContext, decltype(&RequestContextDeleter)> context(static_cast<RequestContext *>(data),
114                                                                               RequestContextDeleter);
115     napi_value undefined = NapiUtils::GetUndefined(env);
116     napi_value argv[EVENT_PARAM_TWO] = {nullptr};
117     if (context->IsParseOK() && context->IsExecOK()) {
118         context->EmitSharedManager(ON_DATA_END, std::make_pair(undefined, undefined));
119         argv[EVENT_PARAM_ZERO] = undefined;
120         argv[EVENT_PARAM_ONE] = HttpExec::RequestInStreamCallback(context.get());
121         if (argv[EVENT_PARAM_ONE] == nullptr) {
122             return;
123         }
124     } else {
125         argv[EVENT_PARAM_ZERO] =
126             NapiUtils::CreateErrorMessage(env, context->GetErrorCode(), context->GetErrorMessage());
127         if (argv[EVENT_PARAM_ZERO] == nullptr) {
128             return;
129         }
130 
131         argv[EVENT_PARAM_ONE] = undefined;
132     }
133 
134     if (context->GetDeferred() != nullptr) {
135         if (context->IsExecOK()) {
136             napi_resolve_deferred(env, context->GetDeferred(), argv[EVENT_PARAM_ONE]);
137         } else {
138             napi_reject_deferred(env, context->GetDeferred(), argv[EVENT_PARAM_ZERO]);
139         }
140         return;
141     }
142     napi_value func = context->GetCallback();
143     if (NapiUtils::GetValueType(env, func) == napi_function) {
144         (void)NapiUtils::CallFunction(env, undefined, func, EVENT_PARAM_TWO, argv);
145     }
146 }
147 
AsyncWorkRequestCallback(napi_env env,napi_status status,void * data)148 static void AsyncWorkRequestCallback(napi_env env, napi_status status, void *data)
149 {
150     if (status != napi_ok) {
151         return;
152     }
153     std::unique_ptr<RequestContext, decltype(&RequestContextDeleter)> context(static_cast<RequestContext *>(data),
154                                                                               RequestContextDeleter);
155     napi_value argv[EVENT_PARAM_TWO] = {nullptr};
156     if (context->IsParseOK() && context->IsExecOK()) {
157         argv[EVENT_PARAM_ZERO] = NapiUtils::GetUndefined(env);
158         argv[EVENT_PARAM_ONE] = HttpExec::RequestCallback(context.get());
159         if (argv[EVENT_PARAM_ONE] == nullptr) {
160             return;
161         }
162     } else {
163         argv[EVENT_PARAM_ZERO] =
164             NapiUtils::CreateErrorMessage(env, context->GetErrorCode(), context->GetErrorMessage());
165         if (argv[EVENT_PARAM_ZERO] == nullptr) {
166             return;
167         }
168 
169         argv[EVENT_PARAM_ONE] = NapiUtils::GetUndefined(env);
170     }
171     napi_value undefined = NapiUtils::GetUndefined(env);
172     if (context->GetDeferred() != nullptr) {
173         if (context->IsExecOK()) {
174             napi_resolve_deferred(env, context->GetDeferred(), argv[EVENT_PARAM_ONE]);
175         } else {
176             napi_reject_deferred(env, context->GetDeferred(), argv[EVENT_PARAM_ZERO]);
177         }
178         return;
179     }
180     napi_value func = context->GetCallback();
181     if (NapiUtils::GetValueType(env, func) == napi_function) {
182         (void)NapiUtils::CallFunction(env, undefined, func, EVENT_PARAM_TWO, argv);
183     }
184 }
185 
AddCurlHandle(CURL * handle,RequestContext * context)186 bool HttpExec::AddCurlHandle(CURL *handle, RequestContext *context)
187 {
188 #if HAS_NETMANAGER_BASE
189     if (handle == nullptr) {
190 #else
191     if (handle == nullptr || staticVariable_.curlMulti == nullptr) {
192 #endif
193         NETSTACK_LOGE("handle nullptr");
194         return false;
195     }
196 
197 #if HAS_NETMANAGER_BASE
198     std::stringstream name;
199     name << HTTP_REQ_TRACE_NAME << "_" << std::this_thread::get_id();
200     context->SetTraceName(name.str());
201     StartAsyncTrace(HITRACE_TAG_NET, context->GetTraceName(), context->GetTaskId());
202     SetServerSSLCertOption(handle, context);
203 
204     static HttpOverCurl::EpollRequestHandler requestHandler;
205 
206     static auto startedCallback = +[](CURL *easyHandle, void *opaqueData) {
207         char *url = nullptr;
208         curl_easy_getinfo(easyHandle, CURLINFO_EFFECTIVE_URL, &url);
209     };
210 
211     static auto responseCallback = +[](CURLMsg *curlMessage, void *opaqueData) {
212         auto context = static_cast<RequestContext *>(opaqueData);
213         HttpExec::HandleCurlData(curlMessage, context);
214     };
215 
216     requestHandler.Process(handle, startedCallback, responseCallback, context);
217     return true;
218 #else
219     std::thread([context, handle] {
220         std::lock_guard guard(staticVariable_.curlMultiMutex);
221         // Do SetServerSSLCertOption here to avoid blocking the main thread.
222 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
223         pthread_setname_np(HTTP_CLIENT_TASK_THREAD);
224 #else
225         pthread_setname_np(pthread_self(), HTTP_CLIENT_TASK_THREAD);
226 #endif
227         SetServerSSLCertOption(handle, context);
228         staticVariable_.infoQueue.emplace(context, handle);
229         staticVariable_.conditionVariable.notify_all();
230     }).detach();
231 
232     return true;
233 #endif
234 }
235 
236 #if !HAS_NETMANAGER_BASE
237 HttpExec::StaticVariable HttpExec::staticVariable_; /* NOLINT */
238 #endif
239 
240 bool HttpExec::RequestWithoutCache(RequestContext *context)
241 {
242 #if !HAS_NETMANAGER_BASE
243     if (!staticVariable_.initialized) {
244         NETSTACK_LOGE("curl not init");
245         return false;
246     }
247 #endif
248 
249     auto handle = curl_easy_init();
250     if (!handle) {
251         NETSTACK_LOGE("Failed to create fetch task");
252         return false;
253     }
254 
255 #if HAS_NETMANAGER_BASE
256     NETSTACK_CURL_EASY_SET_OPTION(handle, CURLOPT_PRIVATE, context, context);
257 #endif
258 
259     std::vector<std::string> vec;
260     std::for_each(context->options.GetHeader().begin(), context->options.GetHeader().end(),
261                   [&vec](const std::pair<std::string, std::string> &p) {
262                       if (!p.second.empty()) {
263                           vec.emplace_back(p.first + HttpConstant::HTTP_HEADER_SEPARATOR + p.second);
264                       } else {
265                           vec.emplace_back(p.first + HttpConstant::HTTP_HEADER_BLANK_SEPARATOR);
266                       }
267                   });
268     context->SetCurlHeaderList(MakeHeaders(vec));
269 
270     if (!SetOption(handle, context, context->GetCurlHeaderList())) {
271         NETSTACK_LOGE("set option failed");
272         return false;
273     }
274 
275     context->response.SetRequestTime(HttpTime::GetNowTimeGMT());
276     context->SetCurlHandle(handle);
277 
278     if (!AddCurlHandle(handle, context)) {
279         NETSTACK_LOGE("add handle failed");
280         return false;
281     }
282 
283     return true;
284 }
285 
286 bool HttpExec::GetCurlDataFromHandle(CURL *handle, RequestContext *context, CURLMSG curlMsg, CURLcode result)
287 {
288     if (curlMsg != CURLMSG_DONE) {
289         NETSTACK_LOGE("taskid=%{public}d, CURLMSG %{public}s", context->GetTaskId(), std::to_string(curlMsg).c_str());
290         context->SetErrorCode(NapiUtils::NETSTACK_NAPI_INTERNAL_ERROR);
291         return false;
292     }
293 
294     if (result != CURLE_OK) {
295         context->SetErrorCode(result);
296         NETSTACK_LOGE("CURLcode result %{public}s", std::to_string(result).c_str());
297         return false;
298     }
299 
300     context->response.SetResponseTime(HttpTime::GetNowTimeGMT());
301 
302     int64_t responseCode;
303     CURLcode code = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode);
304     if (code != CURLE_OK) {
305         context->SetErrorCode(code);
306         return false;
307     }
308     context->response.SetResponseCode(responseCode);
309     NETSTACK_LOGD("responseCode is %{public}s", std::to_string(responseCode).c_str());
310 
311     struct curl_slist *cookies = nullptr;
312     code = curl_easy_getinfo(handle, CURLINFO_COOKIELIST, &cookies);
313     if (code != CURLE_OK) {
314         context->SetErrorCode(code);
315         return false;
316     }
317 
318     std::unique_ptr<struct curl_slist, decltype(&curl_slist_free_all)> cookiesHandle(cookies, curl_slist_free_all);
319     while (cookies) {
320         context->response.AppendCookies(cookies->data, strlen(cookies->data));
321         if (cookies->next != nullptr) {
322             context->response.AppendCookies(HttpConstant::HTTP_LINE_SEPARATOR,
323                                             strlen(HttpConstant::HTTP_LINE_SEPARATOR));
324         }
325         cookies = cookies->next;
326     }
327     return true;
328 }
329 
330 double HttpExec::GetTimingFromCurl(CURL *handle, CURLINFO info)
331 {
332     time_t timing;
333     CURLcode result = curl_easy_getinfo(handle, info, &timing);
334     if (result != CURLE_OK) {
335         NETSTACK_LOGE("Failed to get timing: %{public}d, %{public}s", info, curl_easy_strerror(result));
336         return 0;
337     }
338     return Timing::TimeUtils::Microseconds2Milliseconds(timing);
339 }
340 
341 curl_off_t HttpExec::GetSizeFromCurl(CURL *handle, RequestContext *context)
342 {
343     auto info = CURLINFO_SIZE_DOWNLOAD_T;
344     auto method = context->options.GetMethod();
345     NETSTACK_LOGD("method is %{public}s", method.c_str());
346     if (MethodForPost(method)) {
347         info = CURLINFO_SIZE_UPLOAD_T;
348     }
349 
350     curl_off_t size = 0;
351     CURLcode result = curl_easy_getinfo(handle, info, &size);
352     if (result != CURLE_OK) {
353         NETSTACK_LOGE("Failed to get timing: %{public}d, %{public}s", info, curl_easy_strerror(result));
354         return 0;
355     }
356     return size;
357 }
358 
359 void HttpExec::CacheCurlPerformanceTiming(CURL *handle, RequestContext *context)
360 {
361     auto dnsTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_NAMELOOKUP_TIME_T);
362     auto connectTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_CONNECT_TIME_T);
363     auto tlsTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_APPCONNECT_TIME_T);
364     auto firstSendTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_PRETRANSFER_TIME_T);
365     auto firstRecvTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_STARTTRANSFER_TIME_T);
366     auto totalTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_TOTAL_TIME_T);
367     auto redirectTime = HttpExec::GetTimingFromCurl(handle, CURLINFO_REDIRECT_TIME_T);
368 
369     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_DNS_TIMING, dnsTime);
370     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_TCP_TIMING, connectTime);
371     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_TLS_TIMING, tlsTime);
372     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_FIRST_SEND_TIMING, firstSendTime);
373     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_FIRST_RECEIVE_TIMING, firstRecvTime);
374     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_TOTAL_FINISH_TIMING, totalTime);
375     context->CachePerformanceTimingItem(HttpConstant::RESPONSE_REDIRECT_TIMING, redirectTime);
376 
377     int64_t responseCode = 0;
378     (void)curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode);
379 
380     /*
381     CURL_HTTP_VERSION_NONE         0
382     CURL_HTTP_VERSION_1_0          1
383     CURL_HTTP_VERSION_1_1          2
384     CURL_HTTP_VERSION_2            3
385     */
386     int64_t httpVer = CURL_HTTP_VERSION_NONE;
387     (void)curl_easy_getinfo(handle, CURLINFO_HTTP_VERSION, &httpVer);
388 
389     NETSTACK_LOGI(
390         "taskid=%{public}d"
391         ", size:%{public}" CURL_FORMAT_CURL_OFF_T
392         ", dns:%{public}.3f"
393         ", connect:%{public}.3f"
394         ", tls:%{public}.3f"
395         ", firstSend:%{public}.3f"
396         ", firstRecv:%{public}.3f"
397         ", total:%{public}.3f"
398         ", redirect:%{public}.3f"
399         ", errCode:%{public}d"
400         ", RespCode:%{public}s"
401         ", httpVer:%{public}s"
402         ", method:%{public}s",
403         context->GetTaskId(), GetSizeFromCurl(handle, context), dnsTime, connectTime == 0 ? 0 : connectTime - dnsTime,
404         tlsTime == 0 ? 0 : tlsTime - connectTime,
405         firstSendTime == 0 ? 0 : firstSendTime - std::max({dnsTime, connectTime, tlsTime}),
406         firstRecvTime == 0 ? 0 : firstRecvTime - firstSendTime, totalTime, redirectTime,
407         context->IsExecOK() ? 0: context->GetErrorCode(), std::to_string(responseCode).c_str(),
408         std::to_string(httpVer).c_str(), context->options.GetMethod().c_str());
409 }
410 
411 #if HAS_NETMANAGER_BASE
412 void HttpExec::HandleCurlData(CURLMsg *msg, RequestContext *context)
413 #else
414 void HttpExec::HandleCurlData(CURLMsg *msg)
415 #endif
416 {
417     if (msg == nullptr) {
418         return;
419     }
420 
421     auto handle = msg->easy_handle;
422     if (handle == nullptr) {
423         return;
424     }
425 
426 #if !HAS_NETMANAGER_BASE
427     auto it = staticVariable_.contextMap.find(handle);
428     if (it == staticVariable_.contextMap.end()) {
429         NETSTACK_LOGE("can not find context");
430         return;
431     }
432 
433     auto context = it->second;
434     staticVariable_.contextMap.erase(it);
435     if (context == nullptr) {
436         NETSTACK_LOGE("can not find context");
437         return;
438     }
439 #endif
440     NETSTACK_LOGD("priority = %{public}d", context->options.GetPriority());
441     context->SetExecOK(GetCurlDataFromHandle(handle, context, msg->msg, msg->data.result));
442     CacheCurlPerformanceTiming(handle, context);
443     if (context->IsExecOK()) {
444         CacheProxy proxy(context->options);
445         proxy.WriteResponseToCache(context->response);
446     }
447     if (context->GetSharedManager() == nullptr) {
448         NETSTACK_LOGE("can not find context manager");
449         return;
450     }
451 #if HAS_NETMANAGER_BASE
452     FinishAsyncTrace(HITRACE_TAG_NET, context->GetTraceName(), context->GetTaskId());
453 #endif
454     context->SendNetworkProfiler();
455     if (handle) {
456         (void)curl_easy_cleanup(handle);
457     }
458     if (context->IsRequestInStream()) {
459         NapiUtils::CreateUvQueueWorkByModuleId(
460             context->GetEnv(), std::bind(AsyncWorkRequestInStreamCallback, context->GetEnv(), napi_ok, context),
461             context->GetModuleId());
462     } else {
463         NapiUtils::CreateUvQueueWorkByModuleId(context->GetEnv(),
464                                                std::bind(AsyncWorkRequestCallback, context->GetEnv(), napi_ok, context),
465                                                context->GetModuleId());
466     }
467 }
468 
469 bool HttpExec::ExecRequest(RequestContext *context)
470 {
471     if (!CommonUtils::HasInternetPermission()) {
472         context->SetPermissionDenied(true);
473         return false;
474     }
475     if (context->IsAtomicService() &&
476         !CommonUtils::IsAllowedHostname(context->GetBundleName(), CommonUtils::DOMAIN_TYPE_HTTP_REQUEST,
477                                         context->options.GetUrl())) {
478         context->SetNoAllowedHost(true);
479         return false;
480     }
481     if (context->GetSharedManager()->IsEventDestroy()) {
482         return false;
483     }
484     context->options.SetRequestTime(HttpTime::GetNowTimeGMT());
485     CacheProxy proxy(context->options);
486     if (context->IsUsingCache() && proxy.ReadResponseFromCache(context)) {
487         if (context->GetSharedManager()) {
488             if (context->IsRequestInStream()) {
489                 NapiUtils::CreateUvQueueWorkByModuleId(
490                     context->GetEnv(), std::bind(AsyncWorkRequestInStreamCallback, context->GetEnv(), napi_ok, context),
491                     context->GetModuleId());
492             } else {
493                 NapiUtils::CreateUvQueueWorkByModuleId(
494                     context->GetEnv(), std::bind(AsyncWorkRequestCallback, context->GetEnv(), napi_ok, context),
495                     context->GetModuleId());
496             }
497         }
498         return true;
499     }
500 
501     if (!RequestWithoutCache(context)) {
502         context->SetErrorCode(NapiUtils::NETSTACK_NAPI_INTERNAL_ERROR);
503         if (context->GetSharedManager()) {
504             if (context->IsRequestInStream()) {
505                 NapiUtils::CreateUvQueueWorkByModuleId(
506                     context->GetEnv(), std::bind(AsyncWorkRequestInStreamCallback, context->GetEnv(), napi_ok, context),
507                     context->GetModuleId());
508             } else {
509                 NapiUtils::CreateUvQueueWorkByModuleId(
510                     context->GetEnv(), std::bind(AsyncWorkRequestCallback, context->GetEnv(), napi_ok, context),
511                     context->GetModuleId());
512             }
513         }
514         return false;
515     }
516 
517     return true;
518 }
519 
520 napi_value HttpExec::BuildRequestCallback(RequestContext *context)
521 {
522     napi_value object = NapiUtils::CreateObject(context->GetEnv());
523     if (NapiUtils::GetValueType(context->GetEnv(), object) != napi_object) {
524         return nullptr;
525     }
526 
527     NapiUtils::SetUint32Property(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESPONSE_CODE,
528                                  context->response.GetResponseCode());
529     NapiUtils::SetStringPropertyUtf8(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_COOKIES,
530                                      context->response.GetCookies());
531 
532     napi_value header = MakeResponseHeader(context->GetEnv(), context);
533     if (NapiUtils::GetValueType(context->GetEnv(), header) == napi_object) {
534         NapiUtils::SetNamedProperty(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_HEADER, header);
535     }
536 
537     if (context->options.GetHttpDataType() != HttpDataType::NO_DATA_TYPE && ProcByExpectDataType(object, context)) {
538         return object;
539     }
540 
541     auto contentType = CommonUtils::ToLower(const_cast<std::map<std::string, std::string> &>(
542         context->response.GetHeader())[HttpConstant::HTTP_CONTENT_TYPE]);
543     if (contentType.find(HttpConstant::HTTP_CONTENT_TYPE_OCTET_STREAM) != std::string::npos ||
544         contentType.find(HttpConstant::HTTP_CONTENT_TYPE_IMAGE) != std::string::npos) {
545         void *data = nullptr;
546         auto body = context->response.GetResult();
547         napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(context->GetEnv(), body.size(), &data);
548         if (data != nullptr && arrayBuffer != nullptr) {
549             if (memcpy_s(data, body.size(), body.c_str(), body.size()) != EOK) {
550                 NETSTACK_LOGE("memcpy_s failed!");
551                 return object;
552             }
553             NapiUtils::SetNamedProperty(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT, arrayBuffer);
554         }
555         NapiUtils::SetUint32Property(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT_TYPE,
556                                      static_cast<uint32_t>(HttpDataType::ARRAY_BUFFER));
557         return object;
558     }
559 
560     /* now just support utf8 */
561     NapiUtils::SetStringPropertyUtf8(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT,
562                                      context->response.GetResult());
563     NapiUtils::SetUint32Property(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT_TYPE,
564                                  static_cast<uint32_t>(HttpDataType::STRING));
565     return object;
566 }
567 
568 napi_value HttpExec::RequestCallback(RequestContext *context)
569 {
570     napi_value result = HttpExec::BuildRequestCallback(context);
571     context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_TOTAL_TIMING);
572     context->SetPerformanceTimingToResult(result);
573     return result;
574 }
575 
576 napi_value HttpExec::RequestInStreamCallback(OHOS::NetStack::Http::RequestContext *context)
577 {
578     napi_value number = NapiUtils::CreateUint32(context->GetEnv(), context->response.GetResponseCode());
579     if (NapiUtils::GetValueType(context->GetEnv(), number) != napi_number) {
580         return nullptr;
581     }
582     return number;
583 }
584 
585 std::string HttpExec::MakeUrl(const std::string &url, std::string param, const std::string &extraParam)
586 {
587     if (param.empty()) {
588         param += extraParam;
589     } else {
590         param += HttpConstant::HTTP_URL_PARAM_SEPARATOR;
591         param += extraParam;
592     }
593 
594     if (param.empty()) {
595         return url;
596     }
597 
598     return url + HttpConstant::HTTP_URL_PARAM_START + param;
599 }
600 
601 bool HttpExec::MethodForGet(const std::string &method)
602 {
603     return (method == HttpConstant::HTTP_METHOD_HEAD || method == HttpConstant::HTTP_METHOD_OPTIONS ||
604             method == HttpConstant::HTTP_METHOD_TRACE || method == HttpConstant::HTTP_METHOD_GET ||
605             method == HttpConstant::HTTP_METHOD_CONNECT);
606 }
607 
608 bool HttpExec::MethodForPost(const std::string &method)
609 {
610     return (method == HttpConstant::HTTP_METHOD_POST || method == HttpConstant::HTTP_METHOD_PUT ||
611             method == HttpConstant::HTTP_METHOD_DELETE || method.empty());
612 }
613 
614 bool HttpExec::EncodeUrlParam(std::string &str)
615 {
616     char encoded[4];
617     std::string encodeOut;
618     size_t length = strlen(str.c_str());
619     for (size_t i = 0; i < length; ++i) {
620         auto c = static_cast<uint8_t>(str.c_str()[i]);
621         if (IsUnReserved(c)) {
622             encodeOut += static_cast<char>(c);
623         } else {
624             if (sprintf_s(encoded, sizeof(encoded), "%%%02X", c) < 0) {
625                 return false;
626             }
627             encodeOut += encoded;
628         }
629     }
630 
631     if (str == encodeOut) {
632         return false;
633     }
634     str = encodeOut;
635     return true;
636 }
637 
638 #if !HAS_NETMANAGER_BASE
639 void HttpExec::AddRequestInfo()
640 {
641     std::lock_guard guard(staticVariable_.curlMultiMutex);
642     int num = 0;
643     while (!staticVariable_.infoQueue.empty()) {
644         if (!staticVariable_.runThread || staticVariable_.curlMulti == nullptr) {
645             break;
646         }
647 
648         auto info = staticVariable_.infoQueue.top();
649         staticVariable_.infoQueue.pop();
650         auto ret = curl_multi_add_handle(staticVariable_.curlMulti, info.handle);
651         if (ret == CURLM_OK) {
652             staticVariable_.contextMap[info.handle] = info.context;
653         }
654 
655         ++num;
656         if (num >= CURL_HANDLE_NUM) {
657             break;
658         }
659     }
660 }
661 #endif
662 
663 #if !HAS_NETMANAGER_BASE
664 void HttpExec::RunThread()
665 {
666 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
667     pthread_setname_np(HTTP_TASK_RUN_THREAD);
668 #else
669     pthread_setname_np(pthread_self(), HTTP_TASK_RUN_THREAD);
670 #endif
671     while (staticVariable_.runThread && staticVariable_.curlMulti != nullptr) {
672         AddRequestInfo();
673         SendRequest();
674         ReadResponse();
675         std::this_thread::sleep_for(std::chrono::milliseconds(CURL_TIMEOUT_MS));
676         std::unique_lock l(staticVariable_.curlMultiMutex);
677         staticVariable_.conditionVariable.wait_for(l, std::chrono::seconds(CONDITION_TIMEOUT_S), [] {
678             return !staticVariable_.infoQueue.empty() || !staticVariable_.contextMap.empty();
679         });
680     }
681 }
682 
683 void HttpExec::SendRequest()
684 {
685     std::lock_guard guard(staticVariable_.curlMultiMutex);
686 
687     int runningHandle = 0;
688     int num = 0;
689     do {
690         if (!staticVariable_.runThread || staticVariable_.curlMulti == nullptr) {
691             break;
692         }
693 
694         auto ret = curl_multi_perform(staticVariable_.curlMulti, &runningHandle);
695 
696         if (runningHandle > 0) {
697             ret = curl_multi_poll(staticVariable_.curlMulti, nullptr, 0, CURL_MAX_WAIT_MSECS, nullptr);
698         }
699 
700         if (ret != CURLM_OK) {
701             return;
702         }
703 
704         ++num;
705         if (num >= CURL_HANDLE_NUM) {
706             break;
707         }
708     } while (runningHandle > 0);
709 }
710 
711 void HttpExec::ReadResponse()
712 {
713     std::lock_guard guard(staticVariable_.curlMultiMutex);
714     CURLMsg *msg = nullptr; /* NOLINT */
715     do {
716         if (!staticVariable_.runThread || staticVariable_.curlMulti == nullptr) {
717             break;
718         }
719 
720         int leftMsg;
721         msg = curl_multi_info_read(staticVariable_.curlMulti, &leftMsg);
722         if (msg) {
723             if (msg->msg == CURLMSG_DONE) {
724                 HandleCurlData(msg);
725             }
726             if (msg->easy_handle) {
727                 (void)curl_multi_remove_handle(staticVariable_.curlMulti, msg->easy_handle);
728                 (void)curl_easy_cleanup(msg->easy_handle);
729             }
730         }
731     } while (msg);
732 }
733 #endif
734 
735 void HttpExec::GetGlobalHttpProxyInfo(std::string &host, int32_t &port, std::string &exclusions)
736 {
737 #ifdef HTTP_PROXY_ENABLE
738     char httpProxyHost[SYSPARA_MAX_SIZE] = {0};
739     char httpProxyPort[SYSPARA_MAX_SIZE] = {0};
740     char httpProxyExclusions[SYSPARA_MAX_SIZE] = {0};
741     GetParameter(HTTP_PROXY_HOST_KEY, DEFAULT_HTTP_PROXY_HOST, httpProxyHost, sizeof(httpProxyHost));
742     GetParameter(HTTP_PROXY_PORT_KEY, DEFAULT_HTTP_PROXY_PORT, httpProxyPort, sizeof(httpProxyPort));
743     GetParameter(HTTP_PROXY_EXCLUSIONS_KEY, DEFAULT_HTTP_PROXY_EXCLUSION_LIST, httpProxyExclusions,
744                  sizeof(httpProxyExclusions));
745 
746     host = Base64::Decode(httpProxyHost);
747     if (host == DEFAULT_HTTP_PROXY_HOST) {
748         host = std::string();
749     }
750     exclusions = httpProxyExclusions;
751     if (exclusions == DEFAULT_HTTP_PROXY_EXCLUSION_LIST) {
752         exclusions = std::string();
753     }
754 
755     port = std::atoi(httpProxyPort);
756 #endif
757 }
758 
759 void HttpExec::GetHttpProxyInfo(RequestContext *context, std::string &host, int32_t &port, std::string &exclusions)
760 {
761     if (context->options.GetUsingHttpProxyType() == UsingHttpProxyType::USE_DEFAULT) {
762 #ifdef HAS_NETMANAGER_BASE
763         using namespace NetManagerStandard;
764         HttpProxy httpProxy;
765         NetConnClient::GetInstance().GetDefaultHttpProxy(httpProxy);
766         host = httpProxy.GetHost();
767         port = httpProxy.GetPort();
768         exclusions = CommonUtils::ToString(httpProxy.GetExclusionList());
769 #else
770         GetGlobalHttpProxyInfo(host, port, exclusions);
771 #endif
772     } else if (context->options.GetUsingHttpProxyType() == UsingHttpProxyType::USE_SPECIFIED) {
773         context->options.GetSpecifiedHttpProxy(host, port, exclusions);
774     }
775 }
776 
777 #if !HAS_NETMANAGER_BASE
778 bool HttpExec::Initialize()
779 {
780     std::lock_guard<std::mutex> lock(staticVariable_.mutexForInitialize);
781     if (staticVariable_.initialized) {
782         return true;
783     }
784     NETSTACK_LOGD("call curl_global_init");
785     if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
786         NETSTACK_LOGE("Failed to initialize 'curl'");
787         return false;
788     }
789 
790     staticVariable_.curlMulti = curl_multi_init();
791     if (staticVariable_.curlMulti == nullptr) {
792         NETSTACK_LOGE("Failed to initialize 'curl_multi'");
793         return false;
794     }
795 
796     staticVariable_.workThread = std::thread(RunThread);
797     staticVariable_.initialized = true;
798     return staticVariable_.initialized;
799 }
800 #endif
801 
802 bool HttpExec::SetOtherOption(CURL *curl, OHOS::NetStack::Http::RequestContext *context)
803 {
804     std::string url = context->options.GetUrl();
805     std::string host, exclusions;
806     int32_t port = 0;
807     GetHttpProxyInfo(context, host, port, exclusions);
808     if (!host.empty() && !CommonUtils::IsHostNameExcluded(url, exclusions, ",")) {
809         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PROXY, host.c_str(), context);
810         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PROXYPORT, port, context);
811         auto curlTunnelValue = (url.find("https://") != std::string::npos) ? 1L : 0L;
812         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HTTPPROXYTUNNEL, curlTunnelValue, context);
813         auto proxyType = (host.find("https://") != std::string::npos) ? CURLPROXY_HTTPS : CURLPROXY_HTTP;
814         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PROXYTYPE, proxyType, context);
815     }
816     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2, context);
817     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CIPHER_LIST, TLS12_SECURITY_CIPHER_SUITE, context);
818 #ifdef NETSTACK_PROXY_PASS
819     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PROXYUSERPWD, NETSTACK_PROXY_PASS, context);
820 #endif // NETSTACK_PROXY_PASS
821 
822 #ifdef HTTP_CURL_PRINT_VERBOSE
823     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_VERBOSE, 1L, context);
824 #endif
825 
826 #ifndef WINDOWS_PLATFORM
827     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_ACCEPT_ENCODING, "", context);
828 #endif
829     return true;
830 }
831 
832 bool HttpExec::SetSSLCertOption(CURL *curl, OHOS::NetStack::Http::RequestContext *context)
833 {
834     std::string cert;
835     std::string certType;
836     std::string key;
837     Secure::SecureChar keyPasswd;
838     context->options.GetClientCert(cert, certType, key, keyPasswd);
839     if (cert.empty()) {
840         NETSTACK_LOGD("SetSSLCertOption param is empty.");
841         return false;
842     }
843     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLCERT, cert.c_str(), context);
844     if (!key.empty()) {
845         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLKEY, key.c_str(), context);
846     }
847     if (!certType.empty()) {
848         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLCERTTYPE, certType.c_str(), context);
849     }
850     if (keyPasswd.Length() > 0) {
851         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_KEYPASSWD, keyPasswd.Data(), context);
852     }
853     return true;
854 }
855 
856 CURLcode HttpExec::SslCtxFunction(CURL *curl, void *ssl_ctx, void *parm)
857 {
858 #ifdef HTTP_MULTIPATH_CERT_ENABLE
859     auto certsPath = static_cast<CertsPath *>(parm);
860     if (certsPath == nullptr) {
861         NETSTACK_LOGE("certsPath is null");
862         return CURLE_SSL_CERTPROBLEM;
863     }
864     if (ssl_ctx == nullptr) {
865         NETSTACK_LOGE("ssl_ctx is null");
866         return CURLE_SSL_CERTPROBLEM;
867     }
868 
869     for (const auto &path : certsPath->certPathList) {
870         if (path.empty() || access(path.c_str(), F_OK) != 0) {
871             NETSTACK_LOGD("certificate directory path is not exist");
872             continue;
873         }
874         if (!SSL_CTX_load_verify_locations(static_cast<SSL_CTX *>(ssl_ctx), nullptr, path.c_str())) {
875             NETSTACK_LOGE("loading certificates from directory error.");
876             continue;
877         }
878     }
879     if (access(certsPath->certFile.c_str(), F_OK) != 0) {
880         NETSTACK_LOGD("certificate directory path is not exist");
881     } else if (!SSL_CTX_load_verify_locations(static_cast<SSL_CTX *>(ssl_ctx), certsPath->certFile.c_str(), nullptr)) {
882         NETSTACK_LOGE("loading certificates from context cert error.");
883     }
884 #endif // HTTP_MULTIPATH_CERT_ENABLE
885     return CURLE_OK;
886 }
887 
888 bool HttpExec::SetServerSSLCertOption(CURL *curl, OHOS::NetStack::Http::RequestContext *context)
889 {
890 #ifndef NO_SSL_CERTIFICATION
891 #ifdef HAS_NETMANAGER_BASE
892     auto hostname = CommonUtils::GetHostnameFromURL(context->options.GetUrl());
893 
894 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
895     std::vector<std::string> certs;
896     // add app cert path
897     auto ret = NetManagerStandard::NetConnClient::GetInstance().GetTrustAnchorsForHostName(hostname, certs);
898     if (ret != 0) {
899         NETSTACK_LOGE("GetTrustAnchorsForHostName error. ret [%{public}d]", ret);
900     }
901 #ifdef HTTP_MULTIPATH_CERT_ENABLE
902     // add user cert path
903     certs.emplace_back(USER_CERT_ROOT_PATH);
904     certs.emplace_back(BASE_PATH + std::to_string(getuid() / UID_TRANSFORM_DIVISOR));
905     // add system cert path
906     certs.emplace_back(HttpConstant::HTTP_PREPARE_CA_PATH);
907     context->SetCertsPath(std::move(certs), context->options.GetCaPath());
908     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 1L, context);
909     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 2L, context);
910     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CTX_FUNCTION, SslCtxFunction, context);
911     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CTX_DATA, &context->GetCertsPath(), context);
912     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CAINFO, nullptr, context);
913 #else
914     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CAINFO, nullptr, context);
915     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 0L, context);
916     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 0L, context);
917 #endif // HTTP_MULTIPATH_CERT_ENABLE
918 #else
919     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 0L, context);
920     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 0L, context);
921 #endif //  !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
922     // pin trusted certifcate keys.
923     if (!NetManagerStandard::NetConnClient::GetInstance().IsPinOpenMode(hostname)) {
924         std::string pins;
925         auto ret1 = NetManagerStandard::NetConnClient::GetInstance().GetPinSetForHostName(hostname, pins);
926         if (ret1 != 0 || pins.empty()) {
927             NETSTACK_LOGD("Get no pinset by host name failed");
928         } else {
929             NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PINNEDPUBLICKEY, pins.c_str(), context);
930         }
931     }
932 #else
933     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CAINFO, nullptr, context);
934     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 0L, context);
935     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 0L, context);
936 #endif // HAS_NETMANAGER_BASE
937 #else
938     // in real life, you should buy a ssl certification and rename it to /etc/ssl/cert.pem
939     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 0L, context);
940     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 0L, context);
941 #endif // NO_SSL_CERTIFICATION
942 
943     return true;
944 }
945 
946 bool HttpExec::SetCertPinnerOption(CURL *curl, RequestContext *context)
947 {
948     auto certPIN = context->options.GetCertificatePinning();
949     if (certPIN.empty()) {
950         NETSTACK_LOGD("CertificatePinning is empty");
951         return true;
952     }
953 
954     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PINNEDPUBLICKEY, certPIN.c_str(), context);
955     return true;
956 }
957 
958 bool HttpExec::SetDnsOption(CURL *curl, RequestContext *context)
959 {
960     std::vector<std::string> dnsServers = context->options.GetDnsServers();
961     if (dnsServers.empty()) {
962         return true;
963     }
964     std::string serverList;
965     for (auto &server : dnsServers) {
966         serverList += server + ",";
967         NETSTACK_LOGD("SetDns server: %{public}s", CommonUtils::AnonymizeIp(server).c_str());
968     }
969     serverList.pop_back();
970     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_DNS_SERVERS, serverList.c_str(), context);
971     return true;
972 }
973 
974 bool HttpExec::ParseHostAndPortFromUrl(const std::string &url, std::string &host, uint16_t &port)
975 {
976     CURLU *cu = curl_url();
977     if (!cu) {
978         NETSTACK_LOGE("out of memory");
979         return false;
980     }
981     if (curl_url_set(cu, CURLUPART_URL, url.c_str(), 0)) {
982         NETSTACK_LOGE("not a normalized URL");
983         curl_url_cleanup(cu);
984         return false;
985     }
986     char *chost = nullptr;
987     char *cport = nullptr;
988 
989     (void)curl_url_get(cu, CURLUPART_HOST, &chost, 0);
990     (void)curl_url_get(cu, CURLUPART_PORT, &cport, CURLU_DEFAULT_PORT);
991     if (chost != nullptr) {
992         host = chost;
993         curl_free(chost);
994     }
995     if (cport != nullptr) {
996         port = atoi(cport);
997         curl_free(cport);
998     }
999     curl_url_cleanup(cu);
1000     return !host.empty();
1001 }
1002 
1003 bool HttpExec::SetDnsResolvOption(CURL *curl, RequestContext *context)
1004 {
1005     std::string host = "";
1006     uint16_t port = 0;
1007     if (!ParseHostAndPortFromUrl(context->options.GetUrl(), host, port)) {
1008         NETSTACK_LOGE("get host and port failed");
1009         return true;
1010     }
1011 #ifdef HAS_NETMANAGER_BASE
1012     struct addrinfo *res = nullptr;
1013     int ret = getaddrinfo_hook(host.c_str(), nullptr, nullptr, &res);
1014     if (ret < 0) {
1015         return true;
1016     }
1017 
1018     struct curl_slist *hostSlist = nullptr;
1019     for (struct addrinfo *p = res; p != nullptr; p = p->ai_next) {
1020         char ipstr[INET6_ADDRSTRLEN];
1021         void *addr = nullptr;
1022 
1023         if (p->ai_family == AF_INET) {
1024             struct sockaddr_in *ipv4 = reinterpret_cast<struct sockaddr_in *>(p->ai_addr);
1025             addr = &ipv4->sin_addr;
1026         } else {
1027             struct sockaddr_in6 *ipv6 = reinterpret_cast<struct sockaddr_in6 *>(p->ai_addr);
1028             addr = &ipv6->sin6_addr;
1029         }
1030         if (inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr)) == NULL) {
1031             continue;
1032         }
1033         std::string resolvHost = host + ":" + std::to_string(port) + ":" + ipstr;
1034         hostSlist = curl_slist_append(hostSlist, resolvHost.c_str());
1035     }
1036     freeaddrinfo(res);
1037     if (hostSlist == nullptr) {
1038         NETSTACK_LOGE("no valid ip");
1039         return true;
1040     }
1041     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_RESOLVE, hostSlist, context);
1042     context->SetCurlHostList(hostSlist);
1043 #endif
1044     return true;
1045 }
1046 
1047 bool HttpExec::SetRequestOption(CURL *curl, RequestContext *context)
1048 {
1049     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HTTP_VERSION, context->options.GetHttpVersion(), context);
1050     const std::string range = context->options.GetRangeString();
1051     if (range.empty()) {
1052         // Some servers don't like requests that are made without a user-agent field, so we provide one
1053         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_USERAGENT, HttpConstant::HTTP_DEFAULT_USER_AGENT, context);
1054     } else {
1055         // https://curl.se/libcurl/c/CURLOPT_RANGE.html
1056         if (context->options.GetMethod() == HttpConstant::HTTP_METHOD_PUT) {
1057             context->SetErrorCode(CURLE_RANGE_ERROR);
1058             NETSTACK_LOGE(
1059                 "For HTTP PUT uploads this option should not be used, since it may conflict with other options.");
1060             return false;
1061         }
1062         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_RANGE, range.c_str(), context);
1063     }
1064     if (!context->options.GetDohUrl().empty()) {
1065         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_DOH_URL, context->options.GetDohUrl().c_str(), context);
1066     }
1067 
1068     SetCertPinnerOption(curl, context);
1069     SetDnsOption(curl, context);
1070     SetSSLCertOption(curl, context);
1071     SetMultiPartOption(curl, context);
1072     SetDnsResolvOption(curl, context);
1073     return true;
1074 }
1075 
1076 bool HttpExec::SetOption(CURL *curl, RequestContext *context, struct curl_slist *requestHeader)
1077 {
1078     const std::string &method = context->options.GetMethod();
1079     if (!MethodForGet(method) && !MethodForPost(method)) {
1080         NETSTACK_LOGE("method %{public}s not supported", method.c_str());
1081         return false;
1082     }
1083 
1084     if (context->options.GetMethod() == HttpConstant::HTTP_METHOD_HEAD) {
1085         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_NOBODY, 1L, context);
1086     }
1087 
1088     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, context->options.GetUrl().c_str(), context);
1089 #ifdef HAS_NETMANAGER_BASE
1090     if (!NetSysIsIpv6Enable(0)) {
1091         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4, context);
1092     }
1093 #endif
1094     if (!method.empty()) {
1095         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CUSTOMREQUEST, method.c_str(), context);
1096     }
1097 
1098     if (MethodForPost(method) && !context->options.GetBody().empty()) {
1099         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_POST, 1L, context);
1100         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_POSTFIELDS, context->options.GetBody().c_str(), context);
1101         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_POSTFIELDSIZE, context->options.GetBody().size(), context);
1102     }
1103 
1104     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_XFERINFOFUNCTION, ProgressCallback, context);
1105     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_XFERINFODATA, context, context);
1106     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_NOPROGRESS, 0L, context);
1107 
1108     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_WRITEFUNCTION, OnWritingMemoryBody, context);
1109     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_WRITEDATA, context, context);
1110 
1111     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADERFUNCTION, OnWritingMemoryHeader, context);
1112     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADERDATA, context, context);
1113     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HTTPHEADER, requestHeader, context);
1114     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_FOLLOWLOCATION, 1L, context);
1115 
1116     /* first #undef CURL_DISABLE_COOKIES in curl config */
1117     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_COOKIEFILE, "", context);
1118     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_NOSIGNAL, 1L, context);
1119     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_TIMEOUT_MS, context->options.GetReadTimeout(), context);
1120     NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CONNECTTIMEOUT_MS, context->options.GetConnectTimeout(), context);
1121 
1122     if (!SetRequestOption(curl, context)) {
1123         return false;
1124     }
1125 
1126     if (!SetOtherOption(curl, context)) {
1127         return false;
1128     }
1129     return true;
1130 }
1131 
1132 size_t HttpExec::OnWritingMemoryBody(const void *data, size_t size, size_t memBytes, void *userData)
1133 {
1134     auto context = static_cast<RequestContext *>(userData);
1135     if (context == nullptr || !context->GetSharedManager()) {
1136         return 0;
1137     }
1138     if (context->GetSharedManager()->IsEventDestroy()) {
1139         context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_BODY_TIMING);
1140         return 0;
1141     }
1142     if (context->IsRequestInStream()) {
1143         context->SetTempData(data, size * memBytes);
1144         NapiUtils::CreateUvQueueWorkByModuleId(
1145             context->GetEnv(), std::bind(OnDataReceive, context->GetEnv(), napi_ok, context), context->GetModuleId());
1146         context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_BODY_TIMING);
1147         return size * memBytes;
1148     }
1149     if (context->response.GetResult().size() > context->options.GetMaxLimit() ||
1150         size * memBytes > context->options.GetMaxLimit()) {
1151         NETSTACK_LOGE("response data exceeds the maximum limit");
1152         context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_BODY_TIMING);
1153         return 0;
1154     }
1155     context->response.AppendResult(data, size * memBytes);
1156     context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_BODY_TIMING);
1157     return size * memBytes;
1158 }
1159 
1160 static void MakeSetCookieArray(napi_env env, napi_value header,
1161                                const std::pair<const std::basic_string<char>, std::basic_string<char>> &headerElement)
1162 {
1163     std::vector<std::string> cookieVec =
1164         CommonUtils::Split(headerElement.second, HttpConstant::RESPONSE_KEY_SET_COOKIE_SEPARATOR);
1165     uint32_t index = 0;
1166     auto len = cookieVec.size();
1167     auto array = NapiUtils::CreateArray(env, len);
1168     for (const auto &setCookie : cookieVec) {
1169         auto str = NapiUtils::CreateStringUtf8(env, setCookie);
1170         NapiUtils::SetArrayElement(env, array, index, str);
1171         ++index;
1172     }
1173     NapiUtils::SetArrayProperty(env, header, HttpConstant::RESPONSE_KEY_SET_COOKIE, array);
1174 }
1175 
1176 static void MakeHeaderWithSetCookieArray(napi_env env, napi_value header, std::map<std::string, std::string> *headerMap)
1177 {
1178     for (const auto &it : *headerMap) {
1179         if (!it.first.empty() && !it.second.empty()) {
1180             if (it.first == HttpConstant::RESPONSE_KEY_SET_COOKIE) {
1181                 MakeSetCookieArray(env, header, it);
1182                 continue;
1183             }
1184             NapiUtils::SetStringPropertyUtf8(env, header, it.first, it.second);
1185         }
1186     }
1187 }
1188 
1189 static void ResponseHeaderCallback(uv_work_t *work, int status)
1190 {
1191     (void)status;
1192 
1193     auto workWrapper = static_cast<UvWorkWrapperShared *>(work->data);
1194     napi_env env = workWrapper->env;
1195     auto headerMap = static_cast<std::map<std::string, std::string> *>(workWrapper->data);
1196     auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
1197     std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
1198     napi_value header = NapiUtils::CreateObject(env);
1199     if (NapiUtils::GetValueType(env, header) == napi_object) {
1200         MakeHeaderWithSetCookieArray(env, header, headerMap);
1201     }
1202     std::pair<napi_value, napi_value> arg = {NapiUtils::GetUndefined(env), header};
1203     workWrapper->manager->Emit(workWrapper->type, arg);
1204     delete headerMap;
1205     headerMap = nullptr;
1206     delete workWrapper;
1207     workWrapper = nullptr;
1208     delete work;
1209     work = nullptr;
1210 }
1211 
1212 static std::map<std::string, std::string> MakeHeaderWithSetCookie(RequestContext *context)
1213 {
1214     std::map<std::string, std::string> tempMap = context->response.GetHeader();
1215     std::string setCookies;
1216     size_t loop = 0;
1217     for (const auto &setCookie : context->response.GetsetCookie()) {
1218         setCookies += setCookie;
1219         if (loop + 1 < context->response.GetsetCookie().size()) {
1220             setCookies += HttpConstant::RESPONSE_KEY_SET_COOKIE_SEPARATOR;
1221         }
1222         ++loop;
1223     }
1224     tempMap[HttpConstant::RESPONSE_KEY_SET_COOKIE] = setCookies;
1225     return tempMap;
1226 }
1227 
1228 size_t HttpExec::OnWritingMemoryHeader(const void *data, size_t size, size_t memBytes, void *userData)
1229 {
1230     auto context = static_cast<RequestContext *>(userData);
1231     if (context == nullptr) {
1232         return 0;
1233     }
1234     if (context->GetSharedManager()->IsEventDestroy()) {
1235         context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_HEADER_TIMING);
1236         return 0;
1237     }
1238     context->response.AppendRawHeader(data, size * memBytes);
1239     if (CommonUtils::EndsWith(context->response.GetRawHeader(), HttpConstant::HTTP_RESPONSE_HEADER_SEPARATOR)) {
1240         context->response.ParseHeaders();
1241         if (context->GetSharedManager()) {
1242             auto headerMap = new std::map<std::string, std::string>(MakeHeaderWithSetCookie(context));
1243             context->GetSharedManager()->EmitByUvWithoutCheckShared(ON_HEADER_RECEIVE, headerMap,
1244                                                                     ResponseHeaderCallback);
1245             auto headersMap = new std::map<std::string, std::string>(MakeHeaderWithSetCookie(context));
1246             context->GetSharedManager()->EmitByUvWithoutCheckShared(ON_HEADERS_RECEIVE, headersMap,
1247                                                                     ResponseHeaderCallback);
1248         }
1249     }
1250     context->StopAndCacheNapiPerformanceTiming(HttpConstant::RESPONSE_HEADER_TIMING);
1251     return size * memBytes;
1252 }
1253 
1254 void HttpExec::OnDataReceive(napi_env env, napi_status status, void *data)
1255 {
1256     auto context = static_cast<RequestContext *>(data);
1257     if (context == nullptr) {
1258         NETSTACK_LOGE("context is nullptr");
1259         return;
1260     }
1261 
1262     void *buffer = nullptr;
1263     auto tempData = context->GetTempData();
1264     context->PopTempData();
1265     if (tempData.empty()) {
1266         NETSTACK_LOGI("[GetTempData] tempDate is empty!");
1267         return;
1268     }
1269     napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(context->GetEnv(), tempData.size(), &buffer);
1270     if (buffer == nullptr || arrayBuffer == nullptr) {
1271         return;
1272     }
1273     if (memcpy_s(buffer, tempData.size(), tempData.data(), tempData.size()) != EOK) {
1274         NETSTACK_LOGE("[CreateArrayBuffer] memory copy failed");
1275         return;
1276     }
1277     context->EmitSharedManager(ON_DATA_RECEIVE,
1278                                std::make_pair(NapiUtils::GetUndefined(context->GetEnv()), arrayBuffer));
1279 }
1280 
1281 void HttpExec::OnDataProgress(napi_env env, napi_status status, void *data)
1282 {
1283     auto context = static_cast<RequestContext *>(data);
1284     if (context == nullptr) {
1285         NETSTACK_LOGD("OnDataProgress context is null");
1286         return;
1287     }
1288     auto progress = NapiUtils::CreateObject(context->GetEnv());
1289     if (NapiUtils::GetValueType(context->GetEnv(), progress) == napi_undefined) {
1290         return;
1291     }
1292     auto dlLen = context->GetDlLen();
1293     if (dlLen.tLen && dlLen.nLen) {
1294         NapiUtils::SetUint32Property(context->GetEnv(), progress, "receiveSize", static_cast<uint32_t>(dlLen.nLen));
1295         NapiUtils::SetUint32Property(context->GetEnv(), progress, "totalSize", static_cast<uint32_t>(dlLen.tLen));
1296 
1297         context->EmitSharedManager(ON_DATA_RECEIVE_PROGRESS,
1298                                    std::make_pair(NapiUtils::GetUndefined(context->GetEnv()), progress));
1299     }
1300 }
1301 
1302 __attribute__((no_sanitize("cfi"))) void HttpExec::OnDataUploadProgress(napi_env env, napi_status status, void *data)
1303 {
1304     auto context = static_cast<RequestContext *>(data);
1305     if (context == nullptr) {
1306         NETSTACK_LOGD("OnDataUploadProgress context is null");
1307         return;
1308     }
1309     auto progress = NapiUtils::CreateObject(context->GetEnv());
1310     if (NapiUtils::GetValueType(context->GetEnv(), progress) == napi_undefined) {
1311         NETSTACK_LOGD("OnDataUploadProgress napi_undefined.");
1312         return;
1313     }
1314     NapiUtils::SetUint32Property(context->GetEnv(), progress, "sendSize",
1315                                  static_cast<uint32_t>(context->GetUlLen().nLen));
1316     NapiUtils::SetUint32Property(context->GetEnv(), progress, "totalSize",
1317                                  static_cast<uint32_t>(context->GetUlLen().tLen));
1318     context->EmitSharedManager(ON_DATA_SEND_PROGRESS,
1319                                std::make_pair(NapiUtils::GetUndefined(context->GetEnv()), progress));
1320 }
1321 
1322 __attribute__((no_sanitize("cfi"))) int HttpExec::ProgressCallback(void *userData, curl_off_t dltotal, curl_off_t dlnow,
1323                                                                    curl_off_t ultotal, curl_off_t ulnow)
1324 {
1325     auto context = static_cast<RequestContext *>(userData);
1326     if (context == nullptr) {
1327         return 0;
1328     }
1329     if (ultotal != 0 && ultotal >= ulnow && !context->CompareWithLastElement(ulnow, ultotal)) {
1330         context->SetUlLen(ulnow, ultotal);
1331         NapiUtils::CreateUvQueueWorkByModuleId(context->GetEnv(),
1332                                                std::bind(OnDataUploadProgress, context->GetEnv(), napi_ok, context),
1333                                                context->GetModuleId());
1334     }
1335     if (!context->IsRequestInStream()) {
1336         return 0;
1337     }
1338     if (context->GetSharedManager()->IsEventDestroy()) {
1339         return 0;
1340     }
1341     if (dltotal != 0) {
1342         context->SetDlLen(dlnow, dltotal);
1343         NapiUtils::CreateUvQueueWorkByModuleId(
1344             context->GetEnv(), std::bind(OnDataProgress, context->GetEnv(), napi_ok, context), context->GetModuleId());
1345     }
1346     return 0;
1347 }
1348 
1349 struct curl_slist *HttpExec::MakeHeaders(const std::vector<std::string> &vec)
1350 {
1351     struct curl_slist *header = nullptr;
1352     std::for_each(vec.begin(), vec.end(), [&header](const std::string &s) {
1353         if (!s.empty()) {
1354             header = curl_slist_append(header, s.c_str());
1355         }
1356     });
1357     return header;
1358 }
1359 
1360 napi_value HttpExec::MakeResponseHeader(napi_env env, void *ctx)
1361 {
1362     auto context = reinterpret_cast<RequestContext *>(ctx);
1363     (void)env;
1364     napi_value header = NapiUtils::CreateObject(context->GetEnv());
1365     if (NapiUtils::GetValueType(context->GetEnv(), header) == napi_object) {
1366         for (const auto &it : context->response.GetHeader()) {
1367             if (!it.first.empty() && !it.second.empty()) {
1368                 NapiUtils::SetStringPropertyUtf8(context->GetEnv(), header, it.first, it.second);
1369             }
1370         }
1371         if (!context->response.GetsetCookie().empty()) {
1372             uint32_t index = 0;
1373             auto len = context->response.GetsetCookie().size();
1374             auto array = NapiUtils::CreateArray(context->GetEnv(), len);
1375             for (const auto &setCookie : context->response.GetsetCookie()) {
1376                 auto str = NapiUtils::CreateStringUtf8(context->GetEnv(), setCookie);
1377                 NapiUtils::SetArrayElement(context->GetEnv(), array, index, str);
1378                 ++index;
1379             }
1380             NapiUtils::SetArrayProperty(context->GetEnv(), header, HttpConstant::RESPONSE_KEY_SET_COOKIE, array);
1381         }
1382     }
1383     return header;
1384 }
1385 
1386 bool HttpExec::IsUnReserved(unsigned char in)
1387 {
1388     if ((in >= '0' && in <= '9') || (in >= 'a' && in <= 'z') || (in >= 'A' && in <= 'Z')) {
1389         return true;
1390     }
1391     switch (in) {
1392         case '-':
1393         case '.':
1394         case '_':
1395         case '~':
1396             return true;
1397         default:
1398             break;
1399     }
1400     return false;
1401 }
1402 
1403 bool HttpExec::ProcByExpectDataType(napi_value object, RequestContext *context)
1404 {
1405     switch (context->options.GetHttpDataType()) {
1406         case HttpDataType::STRING: {
1407             NapiUtils::SetStringPropertyUtf8(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT,
1408                                              context->response.GetResult());
1409             NapiUtils::SetUint32Property(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT_TYPE,
1410                                          static_cast<uint32_t>(HttpDataType::STRING));
1411             return true;
1412         }
1413         case HttpDataType::OBJECT: {
1414             if (context->response.GetResult().size() > HttpConstant::MAX_JSON_PARSE_SIZE) {
1415                 return false;
1416             }
1417 
1418             napi_value obj = NapiUtils::JsonParse(context->GetEnv(), context->response.GetResult());
1419             if (obj) {
1420                 NapiUtils::SetNamedProperty(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT, obj);
1421                 NapiUtils::SetUint32Property(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT_TYPE,
1422                                              static_cast<uint32_t>(HttpDataType::OBJECT));
1423                 return true;
1424             }
1425 
1426             // parse maybe failed
1427             return false;
1428         }
1429         case HttpDataType::ARRAY_BUFFER: {
1430             void *data = nullptr;
1431             auto body = context->response.GetResult();
1432             napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(context->GetEnv(), body.size(), &data);
1433             if (data != nullptr && arrayBuffer != nullptr) {
1434                 if (memcpy_s(data, body.size(), body.c_str(), body.size()) < 0) {
1435                     NETSTACK_LOGE("[ProcByExpectDataType] memory copy failed");
1436                     return true;
1437                 }
1438                 NapiUtils::SetNamedProperty(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT, arrayBuffer);
1439                 NapiUtils::SetUint32Property(context->GetEnv(), object, HttpConstant::RESPONSE_KEY_RESULT_TYPE,
1440                                              static_cast<uint32_t>(HttpDataType::ARRAY_BUFFER));
1441             }
1442             return true;
1443         }
1444         default:
1445             break;
1446     }
1447     return false;
1448 }
1449 
1450 void HttpExec::AsyncRunRequest(RequestContext *context)
1451 {
1452     HttpAsyncWork::ExecRequest(context->GetEnv(), context);
1453 }
1454 
1455 #if !HAS_NETMANAGER_BASE
1456 bool HttpExec::IsInitialized()
1457 {
1458     return staticVariable_.initialized;
1459 }
1460 
1461 void HttpExec::DeInitialize()
1462 {
1463     std::lock_guard<std::mutex> lock(staticVariable_.curlMultiMutex);
1464     staticVariable_.runThread = false;
1465     staticVariable_.conditionVariable.notify_all();
1466     if (staticVariable_.workThread.joinable()) {
1467         staticVariable_.workThread.join();
1468     }
1469     if (staticVariable_.curlMulti) {
1470         curl_multi_cleanup(staticVariable_.curlMulti);
1471     }
1472     staticVariable_.initialized = false;
1473 }
1474 #endif
1475 
1476 bool HttpResponseCacheExec::ExecFlush(BaseContext *context)
1477 {
1478     (void)context;
1479     CacheProxy::FlushCache();
1480     return true;
1481 }
1482 
1483 napi_value HttpResponseCacheExec::FlushCallback(BaseContext *context)
1484 {
1485     return NapiUtils::GetUndefined(context->GetEnv());
1486 }
1487 
1488 bool HttpResponseCacheExec::ExecDelete(BaseContext *context)
1489 {
1490     (void)context;
1491     CacheProxy::StopCacheAndDelete();
1492     return true;
1493 }
1494 
1495 napi_value HttpResponseCacheExec::DeleteCallback(BaseContext *context)
1496 {
1497     return NapiUtils::GetUndefined(context->GetEnv());
1498 }
1499 
1500 bool HttpExec::SetMultiPartOption(CURL *curl, RequestContext *context)
1501 {
1502     auto header = context->options.GetHeader();
1503     auto type = CommonUtils::ToLower(header[HttpConstant::HTTP_CONTENT_TYPE]);
1504     if (type != HttpConstant::HTTP_CONTENT_TYPE_MULTIPART) {
1505         return true;
1506     }
1507     auto multiPartDataList = context->options.GetMultiPartDataList();
1508     if (multiPartDataList.empty()) {
1509         return true;
1510     }
1511     curl_mime *multipart = curl_mime_init(curl);
1512     if (multipart == nullptr) {
1513         return false;
1514     }
1515     context->SetMultipart(multipart);
1516     curl_mimepart *part = nullptr;
1517     bool hasData = false;
1518     for (auto &multiFormData : multiPartDataList) {
1519         if (multiFormData.name.empty()) {
1520             continue;
1521         }
1522         if (multiFormData.data.empty() && multiFormData.filePath.empty()) {
1523             NETSTACK_LOGE("Failed to set multiFormData error no data and filepath at the same time");
1524             continue;
1525         }
1526         part = curl_mime_addpart(multipart);
1527         SetFormDataOption(multiFormData, part, curl, context);
1528         hasData = true;
1529     }
1530     if (hasData) {
1531         NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_MIMEPOST, multipart, context);
1532     }
1533     return true;
1534 }
1535 
1536 void HttpExec::SetFormDataOption(MultiFormData &multiFormData, curl_mimepart *part, CURL *curl,
1537                                  RequestContext *context)
1538 {
1539     CURLcode result = curl_mime_name(part, multiFormData.name.c_str());
1540     if (result != CURLE_OK) {
1541         NETSTACK_LOGE("Failed to set name error: %{public}s", curl_easy_strerror(result));
1542         return;
1543     }
1544     if (!multiFormData.contentType.empty()) {
1545         result = curl_mime_type(part, multiFormData.contentType.c_str());
1546         if (result != CURLE_OK) {
1547             NETSTACK_LOGE("Failed to set contentType error: %{public}s", curl_easy_strerror(result));
1548         }
1549     }
1550     if (!multiFormData.remoteFileName.empty()) {
1551         result = curl_mime_filename(part, multiFormData.remoteFileName.c_str());
1552         if (result != CURLE_OK) {
1553             NETSTACK_LOGE("Failed to set remoteFileName error: %{public}s", curl_easy_strerror(result));
1554         }
1555     }
1556     if (!multiFormData.data.empty()) {
1557         result = curl_mime_data(part, multiFormData.data.c_str(), multiFormData.data.length());
1558         if (result != CURLE_OK) {
1559             NETSTACK_LOGE("Failed to set data error: %{public}s", curl_easy_strerror(result));
1560         }
1561     } else {
1562         if (!multiFormData.remoteFileName.empty()) {
1563             std::string fileData;
1564             bool isReadFile = CommonUtils::GetFileDataFromFilePath(multiFormData.filePath.c_str(), fileData);
1565             if (isReadFile) {
1566                 result = curl_mime_data(part, fileData.c_str(), fileData.size());
1567             } else {
1568                 result = curl_mime_filedata(part, multiFormData.filePath.c_str());
1569             }
1570         } else {
1571             result = curl_mime_filedata(part, multiFormData.filePath.c_str());
1572         }
1573         if (result != CURLE_OK) {
1574             NETSTACK_LOGE("Failed to set file data error: %{public}s", curl_easy_strerror(result));
1575         }
1576     }
1577 }
1578 } // namespace OHOS::NetStack::Http
1579