• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "request_context.h"
17 
18 #include <algorithm>
19 
20 #include "constant.h"
21 #include "http_exec.h"
22 #include "napi_utils.h"
23 #include "netstack_common_utils.h"
24 #include "netstack_log.h"
25 #include "secure_char.h"
26 #include "timing.h"
27 
28 static constexpr const int PARAM_JUST_URL = 1;
29 
30 static constexpr const int PARAM_JUST_URL_OR_CALLBACK = 1;
31 
32 static constexpr const int PARAM_URL_AND_OPTIONS_OR_CALLBACK = 2;
33 
34 static constexpr const int PARAM_URL_AND_OPTIONS_AND_CALLBACK = 3;
35 
36 static constexpr const uint32_t DNS_SERVER_SIZE = 3;
37 namespace OHOS::NetStack::Http {
38 static const std::map<int32_t, const char *> HTTP_ERR_MAP = {
39     {HTTP_UNSUPPORTED_PROTOCOL, "Unsupported protocol"},
40     {HTTP_URL_MALFORMAT, "URL using bad/illegal format or missing URL"},
41     {HTTP_COULDNT_RESOLVE_PROXY, "Couldn't resolve proxy name"},
42     {HTTP_COULDNT_RESOLVE_HOST, "Couldn't resolve host name"},
43     {HTTP_COULDNT_CONNECT, "Couldn't connect to server"},
44     {HTTP_WEIRD_SERVER_REPLY, "Weird server reply"},
45     {HTTP_REMOTE_ACCESS_DENIED, "Access denied to remote resource"},
46     {HTTP_HTTP2_ERROR, "Error in the HTTP2 framing layer"},
47     {HTTP_PARTIAL_FILE, "Transferred a partial file"},
48     {HTTP_WRITE_ERROR, "Failed writing received data to disk/application"},
49     {HTTP_UPLOAD_FAILED, "Upload failed"},
50     {HTTP_READ_ERROR, "Failed to open/read local data from file/application"},
51     {HTTP_OUT_OF_MEMORY, "Out of memory"},
52     {HTTP_OPERATION_TIMEDOUT, "Timeout was reached"},
53     {HTTP_TOO_MANY_REDIRECTS, "Number of redirects hit maximum amount"},
54     {HTTP_GOT_NOTHING, "Server returned nothing (no headers, no data)"},
55     {HTTP_SEND_ERROR, "Failed sending data to the peer"},
56     {HTTP_RECV_ERROR, "Failure when receiving data from the peer"},
57     {HTTP_SSL_CERTPROBLEM, "Problem with the local SSL certificate"},
58     {HTTP_SSL_CIPHER, "Couldn't use specified SSL cipher"},
59     {HTTP_PEER_FAILED_VERIFICATION, "SSL peer certificate or SSH remote key was not OK"},
60     {HTTP_BAD_CONTENT_ENCODING, "Unrecognized or bad HTTP Content or Transfer-Encoding"},
61     {HTTP_FILESIZE_EXCEEDED, "Maximum file size exceeded"},
62     {HTTP_REMOTE_DISK_FULL, "Disk full or allocation exceeded"},
63     {HTTP_REMOTE_FILE_EXISTS, "Remote file already exists"},
64     {HTTP_SSL_CACERT_BADFILE, "Problem with the SSL CA cert (path? access rights?)"},
65     {HTTP_REMOTE_FILE_NOT_FOUND, "Remote file not found"},
66     {HTTP_AUTH_ERROR, "An authentication function returned an error"},
67     {HTTP_SSL_PINNEDPUBKEYNOTMATCH, "Specified pinned public key did not match"},
68     {HTTP_UNKNOWN_OTHER_ERROR, "Unknown Other Error"},
69 };
RequestContext(napi_env env,EventManager * manager)70 RequestContext::RequestContext(napi_env env, EventManager *manager)
71     : BaseContext(env, manager),
72       usingCache_(true),
73       requestInStream_(false),
74       curlHeaderList_(nullptr),
75       multipart_(nullptr)
76 {
77     StartTiming();
78 }
79 
StartTiming()80 void RequestContext::StartTiming()
81 {
82     time_t startTime = Timing::TimeUtils::GetNowTimeMicroseconds();
83     timerMap_.RecieveTimer(HttpConstant::RESPONSE_HEADER_TIMING).Start(startTime);
84     timerMap_.RecieveTimer(HttpConstant::RESPONSE_BODY_TIMING).Start(startTime);
85     timerMap_.RecieveTimer(HttpConstant::RESPONSE_TOTAL_TIMING).Start(startTime);
86 }
87 
ParseParams(napi_value * params,size_t paramsCount)88 void RequestContext::ParseParams(napi_value *params, size_t paramsCount)
89 {
90     bool valid = CheckParamsType(params, paramsCount);
91     if (!valid) {
92         if (paramsCount == PARAM_JUST_URL_OR_CALLBACK) {
93             if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) {
94                 SetCallback(params[0]);
95             }
96             return;
97         }
98         if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
99             if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) {
100                 SetCallback(params[1]);
101             }
102             return;
103         }
104         if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
105             if (NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function) {
106                 SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]);
107             }
108             return;
109         }
110         return;
111     }
112 
113     if (paramsCount == PARAM_JUST_URL) {
114         options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
115         SetParseOK(true);
116         return;
117     }
118 
119     if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
120         napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
121         if (type == napi_function) {
122             options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
123             SetParseOK(SetCallback(params[1]) == napi_ok);
124             return;
125         }
126         if (type == napi_object) {
127             UrlAndOptions(params[0], params[1]);
128             return;
129         }
130         return;
131     }
132 
133     if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
134         if (SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) != napi_ok) {
135             return;
136         }
137         UrlAndOptions(params[0], params[1]);
138     }
139 }
140 
CheckParamsType(napi_value * params,size_t paramsCount)141 bool RequestContext::CheckParamsType(napi_value *params, size_t paramsCount)
142 {
143     if (paramsCount == PARAM_JUST_URL) {
144         // just url
145         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string;
146     }
147     if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
148         // should be url, callback or url, options
149         napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
150         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
151                (type == napi_function || type == napi_object);
152     }
153     if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
154         // should be url options and callback
155         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
156                NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object &&
157                NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function;
158     }
159     return false;
160 }
161 
ParseNumberOptions(napi_value optionsValue)162 void RequestContext::ParseNumberOptions(napi_value optionsValue)
163 {
164     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT)) {
165         options.SetReadTimeout(
166             NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT));
167     }
168 
169     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_MAX_LIMIT)) {
170         options.SetMaxLimit(NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_MAX_LIMIT));
171     }
172 
173     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT)) {
174         options.SetConnectTimeout(
175             NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT));
176     }
177 
178     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_CACHE)) {
179         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_CACHE);
180         if (NapiUtils::GetValueType(GetEnv(), value) == napi_boolean) {
181             usingCache_ = NapiUtils::GetBooleanFromValue(GetEnv(), value);
182         }
183     }
184 
185     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_PROTOCOL)) {
186         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_PROTOCOL);
187         if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
188             uint32_t number = NapiUtils::GetUint32FromValue(GetEnv(), value);
189             if (number == static_cast<uint32_t>(HttpProtocol::HTTP1_1) ||
190                 number == static_cast<uint32_t>(HttpProtocol::HTTP2) ||
191                 number == static_cast<uint32_t>(HttpProtocol::HTTP3)) {
192                 options.SetUsingProtocol(static_cast<HttpProtocol>(number));
193             }
194         }
195     }
196     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXPECT_DATA_TYPE)) {
197         napi_value value =
198             NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXPECT_DATA_TYPE);
199         if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
200             uint32_t type = NapiUtils::GetUint32FromValue(GetEnv(), value);
201             options.SetHttpDataType(static_cast<HttpDataType>(type));
202         }
203     }
204 
205     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_PRIORITY)) {
206         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_PRIORITY);
207         if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
208             uint32_t priority = NapiUtils::GetUint32FromValue(GetEnv(), value);
209             options.SetPriority(priority);
210         }
211     }
212 }
213 
ParseHeader(napi_value optionsValue)214 void RequestContext::ParseHeader(napi_value optionsValue)
215 {
216     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER)) {
217         return;
218     }
219     napi_value header = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER);
220     if (NapiUtils::GetValueType(GetEnv(), header) != napi_object) {
221         return;
222     }
223     if (HttpExec::MethodForPost(options.GetMethod())) {
224         options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
225                           HttpConstant::HTTP_CONTENT_TYPE_JSON); // default
226     }
227     auto names = NapiUtils::GetPropertyNames(GetEnv(), header);
228     std::for_each(names.begin(), names.end(), [header, this](const std::string &name) {
229         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), header, name);
230         std::string valueStr = NapiUtils::NapiValueToString(GetEnv(), value);
231         options.SetHeader(CommonUtils::ToLower(name), valueStr);
232     });
233 }
234 
HandleMethodForGet(napi_value extraData)235 bool RequestContext::HandleMethodForGet(napi_value extraData)
236 {
237     std::string url = options.GetUrl();
238     std::string param;
239     auto index = url.find(HttpConstant::HTTP_URL_PARAM_START);
240     if (index != std::string::npos) {
241         param = url.substr(index + 1);
242         url.resize(index);
243     }
244 
245     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
246     if (type == napi_string) {
247         std::string extraParam = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
248 
249         options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
250         return true;
251     }
252     if (type != napi_object) {
253         return true;
254     }
255 
256     std::string extraParam;
257     auto names = NapiUtils::GetPropertyNames(GetEnv(), extraData);
258     std::for_each(names.begin(), names.end(), [this, extraData, &extraParam](std::string name) {
259         auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), extraData, name);
260         NETSTACK_LOGI("url param name = ..., value = ...");
261         if (!name.empty() && !value.empty()) {
262             bool encodeName = HttpExec::EncodeUrlParam(name);
263             bool encodeValue = HttpExec::EncodeUrlParam(value);
264             if (encodeName || encodeValue) {
265                 options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
266                                   HttpConstant::HTTP_CONTENT_TYPE_URL_ENCODE);
267             }
268             extraParam +=
269                 name + HttpConstant::HTTP_URL_NAME_VALUE_SEPARATOR + value + HttpConstant::HTTP_URL_PARAM_SEPARATOR;
270         }
271     });
272     if (!extraParam.empty()) {
273         extraParam.pop_back(); // remove the last &
274     }
275 
276     options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
277     return true;
278 }
279 
ParseExtraData(napi_value optionsValue)280 bool RequestContext::ParseExtraData(napi_value optionsValue)
281 {
282     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA)) {
283         NETSTACK_LOGD("no extraData");
284         return true;
285     }
286 
287     napi_value extraData = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA);
288     if (NapiUtils::GetValueType(GetEnv(), extraData) == napi_undefined ||
289         NapiUtils::GetValueType(GetEnv(), extraData) == napi_null) {
290         NETSTACK_LOGD("extraData is undefined or null");
291         return true;
292     }
293 
294     if (HttpExec::MethodForGet(options.GetMethod())) {
295         return HandleMethodForGet(extraData);
296     }
297 
298     if (HttpExec::MethodForPost(options.GetMethod())) {
299         return GetRequestBody(extraData);
300     }
301     return false;
302 }
303 
ParseUsingHttpProxy(napi_value optionsValue)304 void RequestContext::ParseUsingHttpProxy(napi_value optionsValue)
305 {
306     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_HTTP_PROXY)) {
307         NETSTACK_LOGD("Use default proxy");
308         return;
309     }
310     napi_value httpProxyValue =
311         NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_HTTP_PROXY);
312     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), httpProxyValue);
313     if (type == napi_boolean) {
314         bool usingProxy = NapiUtils::GetBooleanFromValue(GetEnv(), httpProxyValue);
315         UsingHttpProxyType usingType = usingProxy ? UsingHttpProxyType::USE_DEFAULT : UsingHttpProxyType::NOT_USE;
316         options.SetUsingHttpProxyType(usingType);
317         return;
318     }
319     if (type != napi_object) {
320         return;
321     }
322     std::string host = NapiUtils::GetStringPropertyUtf8(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_HOST);
323     int32_t port = NapiUtils::GetInt32Property(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_PORT);
324     std::string exclusionList;
325     if (NapiUtils::HasNamedProperty(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST)) {
326         napi_value exclusionListValue =
327             NapiUtils::GetNamedProperty(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST);
328         uint32_t listLength = NapiUtils::GetArrayLength(GetEnv(), exclusionListValue);
329         for (uint32_t index = 0; index < listLength; ++index) {
330             napi_value exclusionValue = NapiUtils::GetArrayElement(GetEnv(), exclusionListValue, index);
331             std::string exclusion = NapiUtils::GetStringFromValueUtf8(GetEnv(), exclusionValue);
332             if (index != 0) {
333                 exclusionList = exclusionList + HttpConstant::HTTP_PROXY_EXCLUSIONS_SEPARATOR;
334             }
335             exclusionList += exclusion;
336         }
337     }
338     options.SetSpecifiedHttpProxy(host, port, exclusionList);
339     options.SetUsingHttpProxyType(UsingHttpProxyType::USE_SPECIFIED);
340 }
341 
GetRequestBody(napi_value extraData)342 bool RequestContext::GetRequestBody(napi_value extraData)
343 {
344     /* if body is empty, return false, or curl will wait for body */
345 
346     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
347     if (type == napi_string) {
348         auto body = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
349         if (body.empty()) {
350             return false;
351         }
352         options.SetBody(body.c_str(), body.size());
353         return true;
354     }
355 
356     if (NapiUtils::ValueIsArrayBuffer(GetEnv(), extraData)) {
357         size_t length = 0;
358         void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), extraData, &length);
359         if (data == nullptr) {
360             return false;
361         }
362         options.SetBody(data, length);
363         return true;
364     }
365 
366     if (type == napi_object) {
367         std::string body = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), extraData));
368         if (body.empty()) {
369             return false;
370         }
371         options.SetBody(body.c_str(), body.length());
372         return true;
373     }
374 
375     NETSTACK_LOGE("only support string arraybuffer and object");
376     return false;
377 }
378 
ParseCaPath(napi_value optionsValue)379 void RequestContext::ParseCaPath(napi_value optionsValue)
380 {
381     std::string caPath = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CA_PATH);
382     if (!caPath.empty()) {
383         options.SetCaPath(caPath);
384     }
385 }
386 
ParseDohUrl(napi_value optionsValue)387 void RequestContext::ParseDohUrl(napi_value optionsValue)
388 {
389     std::string dohUrl = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_DOH_URL);
390     if (!dohUrl.empty()) {
391         options.SetDohUrl(dohUrl);
392     }
393 }
394 
ParseResumeFromToNumber(napi_value optionsValue)395 void RequestContext::ParseResumeFromToNumber(napi_value optionsValue)
396 {
397     napi_env env = GetEnv();
398     int64_t from = NapiUtils::GetInt64Property(env, optionsValue, HttpConstant::PARAM_KEY_RESUME_FROM);
399     int64_t to = NapiUtils::GetInt64Property(env, optionsValue, HttpConstant::PARAM_KEY_RESUME_TO);
400     options.SetRangeNumber(from, to);
401 }
402 
UrlAndOptions(napi_value urlValue,napi_value optionsValue)403 void RequestContext::UrlAndOptions(napi_value urlValue, napi_value optionsValue)
404 {
405     options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), urlValue));
406 
407     std::string method = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD);
408     if (method.empty()) {
409         method = HttpConstant::HTTP_METHOD_GET;
410     }
411     options.SetMethod(method);
412 
413     ParseNumberOptions(optionsValue);
414     ParseUsingHttpProxy(optionsValue);
415     ParseClientCert(optionsValue);
416 
417     /* parse extra data here to recover header */
418     if (!ParseExtraData(optionsValue)) {
419         return;
420     }
421 
422     ParseHeader(optionsValue);
423     ParseCaPath(optionsValue);
424     ParseDohUrl(optionsValue);
425     ParseResumeFromToNumber(optionsValue);
426     ParseDnsServers(optionsValue);
427     ParseMultiFormData(optionsValue);
428     SetParseOK(true);
429 }
430 
IsUsingCache() const431 bool RequestContext::IsUsingCache() const
432 {
433     return usingCache_;
434 }
435 
SetCurlHeaderList(struct curl_slist * curlHeaderList)436 void RequestContext::SetCurlHeaderList(struct curl_slist *curlHeaderList)
437 {
438     curlHeaderList_ = curlHeaderList;
439 }
440 
GetCurlHeaderList()441 struct curl_slist *RequestContext::GetCurlHeaderList()
442 {
443     return curlHeaderList_;
444 }
~RequestContext()445 RequestContext::~RequestContext()
446 {
447     if (curlHeaderList_ != nullptr) {
448         curl_slist_free_all(curlHeaderList_);
449     }
450     if (multipart_ != nullptr) {
451         curl_mime_free(multipart_);
452         multipart_ = nullptr;
453     }
454     NETSTACK_LOGD("RequestContext is destructed by the destructor");
455 }
456 
SetCacheResponse(const HttpResponse & cacheResponse)457 void RequestContext::SetCacheResponse(const HttpResponse &cacheResponse)
458 {
459     cacheResponse_ = cacheResponse;
460 }
SetResponseByCache()461 void RequestContext::SetResponseByCache()
462 {
463     response = cacheResponse_;
464 }
465 
GetErrorCode() const466 int32_t RequestContext::GetErrorCode() const
467 {
468     auto err = BaseContext::GetErrorCode();
469     if (err == PARSE_ERROR_CODE) {
470         return PARSE_ERROR_CODE;
471     }
472 
473     if (BaseContext::IsPermissionDenied()) {
474         return PERMISSION_DENIED_CODE;
475     }
476 
477     if (HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE) != HTTP_ERR_MAP.end()) {
478         return err + HTTP_ERROR_CODE_BASE;
479     }
480     return HTTP_UNKNOWN_OTHER_ERROR;
481 }
482 
GetErrorMessage() const483 std::string RequestContext::GetErrorMessage() const
484 {
485     auto err = BaseContext::GetErrorCode();
486     if (err == PARSE_ERROR_CODE) {
487         return PARSE_ERROR_MSG;
488     }
489 
490     if (BaseContext::IsPermissionDenied()) {
491         return PERMISSION_DENIED_MSG;
492     }
493 
494     auto pos = HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE);
495     if (pos != HTTP_ERR_MAP.end()) {
496         return pos->second;
497     }
498     return HTTP_ERR_MAP.at(HTTP_UNKNOWN_OTHER_ERROR);
499 }
500 
EnableRequestInStream()501 void RequestContext::EnableRequestInStream()
502 {
503     requestInStream_ = true;
504 }
505 
IsRequestInStream() const506 bool RequestContext::IsRequestInStream() const
507 {
508     return requestInStream_;
509 }
510 
SetDlLen(curl_off_t nowLen,curl_off_t totalLen)511 void RequestContext::SetDlLen(curl_off_t nowLen, curl_off_t totalLen)
512 {
513     std::lock_guard<std::mutex> lock(dlLenLock_);
514     LoadBytes dlBytes{nowLen, totalLen};
515     dlBytes_.push(dlBytes);
516 }
517 
518 
GetDlLen()519 LoadBytes RequestContext::GetDlLen()
520 {
521     std::lock_guard<std::mutex> lock(dlLenLock_);
522     LoadBytes dlBytes;
523     if (!dlBytes_.empty()) {
524         dlBytes.nLen = dlBytes_.front().nLen;
525         dlBytes.tLen = dlBytes_.front().tLen;
526         dlBytes_.pop();
527     }
528     return dlBytes;
529 }
530 
SetUlLen(curl_off_t nowLen,curl_off_t totalLen)531 void RequestContext::SetUlLen(curl_off_t nowLen, curl_off_t totalLen)
532 {
533     std::lock_guard<std::mutex> lock(ulLenLock_);
534     if (!ulBytes_.empty()) {
535         ulBytes_.pop();
536     }
537     LoadBytes ulBytes{nowLen, totalLen};
538     ulBytes_.push(ulBytes);
539 }
540 
GetUlLen()541 LoadBytes RequestContext::GetUlLen()
542 {
543     std::lock_guard<std::mutex> lock(ulLenLock_);
544     LoadBytes ulBytes;
545     if (!ulBytes_.empty()) {
546         ulBytes.nLen = ulBytes_.back().nLen;
547         ulBytes.tLen = ulBytes_.back().tLen;
548     }
549     return ulBytes;
550 }
551 
CompareWithLastElement(curl_off_t nowLen,curl_off_t totalLen)552 bool RequestContext::CompareWithLastElement(curl_off_t nowLen, curl_off_t totalLen)
553 {
554     std::lock_guard<std::mutex> lock(ulLenLock_);
555     if (ulBytes_.empty()) {
556         return false;
557     }
558     const LoadBytes &lastElement = ulBytes_.back();
559     return nowLen == lastElement.nLen && totalLen == lastElement.tLen;
560 }
561 
SetTempData(const void * data,size_t size)562 void RequestContext::SetTempData(const void *data, size_t size)
563 {
564     std::lock_guard<std::mutex> lock(tempDataLock_);
565     std::string tempString;
566     tempString.append(reinterpret_cast<const char *>(data), size);
567     tempData_.push(tempString);
568 }
569 
GetTempData()570 std::string RequestContext::GetTempData()
571 {
572     std::lock_guard<std::mutex> lock(tempDataLock_);
573     if (!tempData_.empty()) {
574         return tempData_.front();
575     }
576     return {};
577 }
578 
PopTempData()579 void RequestContext::PopTempData()
580 {
581     std::lock_guard<std::mutex> lock(tempDataLock_);
582     if (!tempData_.empty()) {
583         tempData_.pop();
584     }
585 }
586 
ParseDnsServers(napi_value optionsValue)587 void RequestContext::ParseDnsServers(napi_value optionsValue)
588 {
589     napi_env env = GetEnv();
590     if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_DNS_SERVERS)) {
591         NETSTACK_LOGD("ParseDnsServers no data");
592         return;
593     }
594     napi_value dnsServerValue = NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_DNS_SERVERS);
595     if (NapiUtils::GetValueType(env, dnsServerValue) != napi_object) {
596         return;
597     }
598     uint32_t dnsLength = NapiUtils::GetArrayLength(env, dnsServerValue);
599     if (dnsLength == 0) {
600         return;
601     }
602     std::vector<std::string> dnsServers;
603     uint32_t dnsSize = 0;
604     for (uint32_t i = 0; i < dnsLength && dnsSize < DNS_SERVER_SIZE; i++) {
605         napi_value element = NapiUtils::GetArrayElement(env, dnsServerValue, i);
606         std::string dnsServer = NapiUtils::GetStringFromValueUtf8(env, element);
607         if (dnsServer.length() == 0) {
608             continue;
609         }
610         if (!CommonUtils::IsValidIPV4(dnsServer) && !CommonUtils::IsValidIPV6(dnsServer)) {
611             continue;
612         }
613         dnsServers.push_back(dnsServer);
614         dnsSize++;
615     }
616     if (dnsSize == 0 || dnsServers.data() == nullptr || dnsServers.empty()) {
617         NETSTACK_LOGD("dnsServersArray is empty.");
618         return;
619     }
620     options.SetDnsServers(dnsServers);
621     NETSTACK_LOGD("SetDnsServers success");
622 }
623 
CachePerformanceTimingItem(const std::string & key,double value)624 void RequestContext::CachePerformanceTimingItem(const std::string &key, double value)
625 {
626     performanceTimingMap_[key] = value;
627 }
628 
StopAndCacheNapiPerformanceTiming(const char * key)629 void RequestContext::StopAndCacheNapiPerformanceTiming(const char *key)
630 {
631     Timing::Timer &timer = timerMap_.RecieveTimer(key);
632     timer.Stop();
633     CachePerformanceTimingItem(key, timer.Elapsed());
634 }
635 
SetPerformanceTimingToResult(napi_value result)636 void RequestContext::SetPerformanceTimingToResult(napi_value result)
637 {
638     if (performanceTimingMap_.empty()) {
639         NETSTACK_LOGD("Get performanceTiming data is empty.");
640         return;
641     }
642     napi_value performanceTimingValue;
643     napi_env env = GetEnv();
644     napi_create_object(env, &performanceTimingValue);
645     for (const auto& pair : performanceTimingMap_) {
646         NapiUtils::SetDoubleProperty(env, performanceTimingValue, pair.first, pair.second);
647     }
648     NapiUtils::SetNamedProperty(env, result, HttpConstant::RESPONSE_PERFORMANCE_TIMING, performanceTimingValue);
649 }
650 
ParseClientCert(napi_value optionsValue)651 void RequestContext::ParseClientCert(napi_value optionsValue)
652 {
653     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CLIENT_CERT)) {
654         return;
655     }
656     napi_value clientCertValue =
657         NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CLIENT_CERT);
658     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), clientCertValue);
659     if (type != napi_object) {
660         return;
661     }
662     std::string cert = NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_CERT);
663     std::string certType =
664         NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_CERT_TYPE);
665     std::string key = NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_KEY);
666     Secure::SecureChar keyPasswd = Secure::SecureChar(
667         NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_KEY_PASSWD));
668     options.SetClientCert(cert, certType, key, keyPasswd);
669 }
670 
ParseMultiFormData(napi_value optionsValue)671 void RequestContext::ParseMultiFormData(napi_value optionsValue)
672 {
673     napi_env env = GetEnv();
674     if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST)) {
675         NETSTACK_LOGD("ParseMultiFormData multiFormDataList is null.");
676         return;
677     }
678     napi_value multiFormDataListValue =
679         NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST);
680     if (NapiUtils::GetValueType(env, multiFormDataListValue) != napi_object) {
681         NETSTACK_LOGD("ParseMultiFormData multiFormDataList type is not object.");
682         return;
683     }
684     uint32_t dataLength = NapiUtils::GetArrayLength(env, multiFormDataListValue);
685     if (dataLength == 0) {
686         NETSTACK_LOGD("ParseMultiFormData multiFormDataList length is 0.");
687         return;
688     }
689     for (uint32_t i = 0; i < dataLength; i++) {
690         napi_value formDataValue = NapiUtils::GetArrayElement(env, multiFormDataListValue, i);
691         MultiFormData multiFormData = NapiValue2FormData(formDataValue);
692         options.AddMultiFormData(multiFormData);
693     }
694 }
695 
NapiValue2FormData(napi_value formDataValue)696 MultiFormData RequestContext::NapiValue2FormData(napi_value formDataValue)
697 {
698     napi_env env = GetEnv();
699     MultiFormData multiFormData;
700     multiFormData.name = NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_NAME);
701     multiFormData.contentType =
702         NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_CONTENT_TYPE);
703     multiFormData.remoteFileName =
704         NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_REMOTE_FILE_NAME);
705     RequestContext::SaveFormData(
706         env, NapiUtils::GetNamedProperty(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_DATA), multiFormData);
707     multiFormData.filePath =
708         NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_FILE_PATH);
709     return multiFormData;
710 }
711 
SaveFormData(napi_env env,napi_value dataValue,MultiFormData & multiFormData)712 void RequestContext::SaveFormData(napi_env env, napi_value dataValue, MultiFormData &multiFormData)
713 {
714     napi_valuetype type = NapiUtils::GetValueType(env, dataValue);
715     if (type == napi_string) {
716         multiFormData.data = NapiUtils::GetStringFromValueUtf8(GetEnv(), dataValue);
717         NETSTACK_LOGD("SaveFormData string");
718     } else if (NapiUtils::ValueIsArrayBuffer(GetEnv(), dataValue)) {
719         size_t length = 0;
720         void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), dataValue, &length);
721         if (data == nullptr) {
722             return;
723         }
724         multiFormData.data = std::string(static_cast<const char *>(data), length);
725         NETSTACK_LOGD("SaveFormData ArrayBuffer");
726     } else if (type == napi_object) {
727         multiFormData.data = NapiUtils::GetStringFromValueUtf8(
728             GetEnv(), NapiUtils::JsonStringify(GetEnv(), dataValue));
729         NETSTACK_LOGD("SaveFormData Object");
730     } else {
731         NETSTACK_LOGD("only support string, ArrayBuffer and Object");
732     }
733 }
734 
SetMultipart(curl_mime * multipart)735 void RequestContext::SetMultipart(curl_mime *multipart)
736 {
737     multipart_ = multipart;
738 }
739 } // namespace OHOS::NetStack::Http
740