• 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 #include <atomic>
20 #include <limits>
21 #include <utility>
22 #include <sstream>
23 
24 #include "constant.h"
25 #include "http_exec.h"
26 #include "napi_utils.h"
27 #include "netstack_common_utils.h"
28 #include "netstack_log.h"
29 #include "secure_char.h"
30 #include "timing.h"
31 #if HAS_NETMANAGER_BASE
32 #include "http_network_message.h"
33 #endif
34 
35 static constexpr const int PARAM_JUST_URL = 1;
36 
37 static constexpr const int PARAM_JUST_URL_OR_CALLBACK = 1;
38 
39 static constexpr const int PARAM_URL_AND_OPTIONS_OR_CALLBACK = 2;
40 
41 static constexpr const int PARAM_URL_AND_OPTIONS_AND_CALLBACK = 3;
42 
43 static constexpr const uint32_t DNS_SERVER_SIZE = 3;
44 namespace OHOS::NetStack::Http {
45 static const std::map<int32_t, const char *> HTTP_ERR_MAP = {
46     {HTTP_UNSUPPORTED_PROTOCOL, "Unsupported protocol"},
47     {HTTP_URL_MALFORMAT, "URL using bad/illegal format or missing URL"},
48     {HTTP_COULDNT_RESOLVE_PROXY, "Couldn't resolve proxy name"},
49     {HTTP_COULDNT_RESOLVE_HOST, "Couldn't resolve host name"},
50     {HTTP_COULDNT_CONNECT, "Couldn't connect to server"},
51     {HTTP_WEIRD_SERVER_REPLY, "Weird server reply"},
52     {HTTP_REMOTE_ACCESS_DENIED, "Access denied to remote resource"},
53     {HTTP_HTTP2_ERROR, "Error in the HTTP2 framing layer"},
54     {HTTP_PARTIAL_FILE, "Transferred a partial file"},
55     {HTTP_WRITE_ERROR, "Failed writing received data to disk/application"},
56     {HTTP_UPLOAD_FAILED, "Upload failed"},
57     {HTTP_READ_ERROR, "Failed to open/read local data from file/application"},
58     {HTTP_OUT_OF_MEMORY, "Out of memory"},
59     {HTTP_OPERATION_TIMEDOUT, "Timeout was reached"},
60     {HTTP_TOO_MANY_REDIRECTS, "Number of redirects hit maximum amount"},
61     {HTTP_GOT_NOTHING, "Server returned nothing (no headers, no data)"},
62     {HTTP_SEND_ERROR, "Failed sending data to the peer"},
63     {HTTP_RECV_ERROR, "Failure when receiving data from the peer"},
64     {HTTP_SSL_CERTPROBLEM, "Problem with the local SSL certificate"},
65     {HTTP_SSL_CIPHER, "Couldn't use specified SSL cipher"},
66     {HTTP_PEER_FAILED_VERIFICATION, "SSL peer certificate or SSH remote key was not OK"},
67     {HTTP_BAD_CONTENT_ENCODING, "Unrecognized or bad HTTP Content or Transfer-Encoding"},
68     {HTTP_FILESIZE_EXCEEDED, "Maximum file size exceeded"},
69     {HTTP_REMOTE_DISK_FULL, "Disk full or allocation exceeded"},
70     {HTTP_REMOTE_FILE_EXISTS, "Remote file already exists"},
71     {HTTP_SSL_CACERT_BADFILE, "Problem with the SSL CA cert (path? access rights?)"},
72     {HTTP_REMOTE_FILE_NOT_FOUND, "Remote file not found"},
73     {HTTP_AUTH_ERROR, "An authentication function returned an error"},
74     {HTTP_SSL_PINNEDPUBKEYNOTMATCH, "Specified pinned public key did not match"},
75     {HTTP_NOT_ALLOWED_HOST, "It is not allowed to access this domain"},
76     {HTTP_UNKNOWN_OTHER_ERROR, "Unknown Other Error"},
77 };
78 static std::atomic<int32_t> g_currentTaskId = std::numeric_limits<int32_t>::min();
RequestContext(napi_env env,EventManager * manager)79 RequestContext::RequestContext(napi_env env, EventManager *manager)
80     : BaseContext(env, manager),
81       usingCache_(true),
82       requestInStream_(false),
83       curlHeaderList_(nullptr),
84       multipart_(nullptr),
85       curlHostList_(nullptr)
86 {
87     taskId_ = g_currentTaskId++;
88     isAtomicService_ = false;
89     bundleName_ = "";
90     StartTiming();
91 #if HAS_NETMANAGER_BASE
92     networkProfilerUtils_ = std::make_unique<NetworkProfilerUtils>();
93 #endif
94 }
95 
StartTiming()96 void RequestContext::StartTiming()
97 {
98     time_t startTime = Timing::TimeUtils::GetNowTimeMicroseconds();
99     timerMap_.RecieveTimer(HttpConstant::RESPONSE_HEADER_TIMING).Start(startTime);
100     timerMap_.RecieveTimer(HttpConstant::RESPONSE_BODY_TIMING).Start(startTime);
101     timerMap_.RecieveTimer(HttpConstant::RESPONSE_TOTAL_TIMING).Start(startTime);
102 
103     // init RESPONSE_HEADER_TIMING and RESPONSE_BODY_TIMING
104     performanceTimingMap_[HttpConstant::RESPONSE_HEADER_TIMING] = 0.0;
105     performanceTimingMap_[HttpConstant::RESPONSE_BODY_TIMING] = 0.0;
106 }
107 
ParseParams(napi_value * params,size_t paramsCount)108 void RequestContext::ParseParams(napi_value *params, size_t paramsCount)
109 {
110     bool valid = CheckParamsType(params, paramsCount);
111     if (!valid) {
112         if (paramsCount == PARAM_JUST_URL_OR_CALLBACK) {
113             if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) {
114                 SetCallback(params[0]);
115             }
116             return;
117         }
118         if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
119             if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) {
120                 SetCallback(params[1]);
121             }
122             return;
123         }
124         if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
125             if (NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function) {
126                 SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]);
127             }
128             return;
129         }
130         return;
131     }
132 
133     if (paramsCount == PARAM_JUST_URL) {
134         options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
135         SetParseOK(true);
136         return;
137     }
138 
139     if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
140         napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
141         if (type == napi_function) {
142             options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
143             SetParseOK(SetCallback(params[1]) == napi_ok);
144             return;
145         }
146         if (type == napi_object) {
147             UrlAndOptions(params[0], params[1]);
148             return;
149         }
150         return;
151     }
152 
153     if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
154         if (SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) != napi_ok) {
155             return;
156         }
157         UrlAndOptions(params[0], params[1]);
158     }
159 }
160 
CheckParamsType(napi_value * params,size_t paramsCount)161 bool RequestContext::CheckParamsType(napi_value *params, size_t paramsCount)
162 {
163     if (paramsCount == PARAM_JUST_URL) {
164         // just url
165         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string;
166     }
167     if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
168         // should be url, callback or url, options
169         napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
170         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
171                (type == napi_function || type == napi_object);
172     }
173     if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
174         // should be url options and callback
175         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
176                NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object &&
177                NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function;
178     }
179     return false;
180 }
181 
ParseNumberOptions(napi_value optionsValue)182 void RequestContext::ParseNumberOptions(napi_value optionsValue)
183 {
184     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT)) {
185         options.SetReadTimeout(
186             NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT));
187     }
188 
189     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_MAX_LIMIT)) {
190         options.SetMaxLimit(NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_MAX_LIMIT));
191     }
192 
193     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT)) {
194         options.SetConnectTimeout(
195             NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT));
196     }
197 
198     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_CACHE)) {
199         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_CACHE);
200         if (NapiUtils::GetValueType(GetEnv(), value) == napi_boolean) {
201             usingCache_ = NapiUtils::GetBooleanFromValue(GetEnv(), value);
202         }
203     }
204 
205     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_PROTOCOL)) {
206         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_PROTOCOL);
207         if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
208             uint32_t number = NapiUtils::GetUint32FromValue(GetEnv(), value);
209             if (number == static_cast<uint32_t>(HttpProtocol::HTTP1_1) ||
210                 number == static_cast<uint32_t>(HttpProtocol::HTTP2) ||
211                 number == static_cast<uint32_t>(HttpProtocol::HTTP3)) {
212                 options.SetUsingProtocol(static_cast<HttpProtocol>(number));
213             }
214         }
215     }
216     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXPECT_DATA_TYPE)) {
217         napi_value value =
218             NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXPECT_DATA_TYPE);
219         if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
220             uint32_t type = NapiUtils::GetUint32FromValue(GetEnv(), value);
221             options.SetHttpDataType(static_cast<HttpDataType>(type));
222         }
223     }
224 
225     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_PRIORITY)) {
226         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_PRIORITY);
227         if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
228             uint32_t priority = NapiUtils::GetUint32FromValue(GetEnv(), value);
229             options.SetPriority(priority);
230         }
231     }
232 }
233 
ParseHeader(napi_value optionsValue)234 void RequestContext::ParseHeader(napi_value optionsValue)
235 {
236     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER)) {
237         return;
238     }
239     napi_value header = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER);
240     if (NapiUtils::GetValueType(GetEnv(), header) != napi_object) {
241         return;
242     }
243     if (HttpExec::MethodForPost(options.GetMethod())) {
244         options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
245                           HttpConstant::HTTP_CONTENT_TYPE_JSON); // default
246     }
247     auto names = NapiUtils::GetPropertyNames(GetEnv(), header);
248     std::for_each(names.begin(), names.end(), [header, this](const std::string &name) {
249         napi_value value = NapiUtils::GetNamedProperty(GetEnv(), header, name);
250         std::string valueStr = NapiUtils::NapiValueToString(GetEnv(), value);
251         options.SetHeader(CommonUtils::ToLower(name), valueStr);
252     });
253 }
254 
HandleMethodForGet(napi_value extraData)255 bool RequestContext::HandleMethodForGet(napi_value extraData)
256 {
257     std::string url = options.GetUrl();
258     std::string param;
259     auto index = url.find(HttpConstant::HTTP_URL_PARAM_START);
260     if (index != std::string::npos) {
261         param = url.substr(index + 1);
262         url.resize(index);
263     }
264 
265     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
266     if (type == napi_string) {
267         std::string extraParam = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
268 
269         options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
270         return true;
271     }
272     if (type != napi_object) {
273         return true;
274     }
275 
276     std::string extraParam;
277     auto names = NapiUtils::GetPropertyNames(GetEnv(), extraData);
278     std::for_each(names.begin(), names.end(), [this, extraData, &extraParam](std::string name) {
279         auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), extraData, name);
280         if (!name.empty() && !value.empty()) {
281             bool encodeName = HttpExec::EncodeUrlParam(name);
282             bool encodeValue = HttpExec::EncodeUrlParam(value);
283             if (encodeName || encodeValue) {
284                 options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
285                                   HttpConstant::HTTP_CONTENT_TYPE_URL_ENCODE);
286             }
287             extraParam +=
288                 name + HttpConstant::HTTP_URL_NAME_VALUE_SEPARATOR + value + HttpConstant::HTTP_URL_PARAM_SEPARATOR;
289         }
290     });
291     if (!extraParam.empty()) {
292         extraParam.pop_back(); // remove the last &
293     }
294 
295     options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
296     return true;
297 }
298 
ParseExtraData(napi_value optionsValue)299 bool RequestContext::ParseExtraData(napi_value optionsValue)
300 {
301     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA)) {
302         NETSTACK_LOGD("no extraData");
303         return true;
304     }
305 
306     napi_value extraData = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA);
307     if (NapiUtils::GetValueType(GetEnv(), extraData) == napi_undefined ||
308         NapiUtils::GetValueType(GetEnv(), extraData) == napi_null) {
309         NETSTACK_LOGD("extraData is undefined or null");
310         return true;
311     }
312 
313     if (HttpExec::MethodForGet(options.GetMethod())) {
314         return HandleMethodForGet(extraData);
315     }
316 
317     if (HttpExec::MethodForPost(options.GetMethod())) {
318         return GetRequestBody(extraData);
319     }
320     return false;
321 }
322 
ParseUsingHttpProxy(napi_value optionsValue)323 void RequestContext::ParseUsingHttpProxy(napi_value optionsValue)
324 {
325     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_HTTP_PROXY)) {
326         NETSTACK_LOGD("Use default proxy");
327         return;
328     }
329     napi_value httpProxyValue =
330         NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_HTTP_PROXY);
331     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), httpProxyValue);
332     if (type == napi_boolean) {
333         bool usingProxy = NapiUtils::GetBooleanFromValue(GetEnv(), httpProxyValue);
334         UsingHttpProxyType usingType = usingProxy ? UsingHttpProxyType::USE_DEFAULT : UsingHttpProxyType::NOT_USE;
335         options.SetUsingHttpProxyType(usingType);
336         return;
337     }
338     if (type != napi_object) {
339         return;
340     }
341     std::string host = NapiUtils::GetStringPropertyUtf8(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_HOST);
342     int32_t port = NapiUtils::GetInt32Property(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_PORT);
343     std::string exclusionList;
344     if (NapiUtils::HasNamedProperty(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST)) {
345         napi_value exclusionListValue =
346             NapiUtils::GetNamedProperty(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST);
347         uint32_t listLength = NapiUtils::GetArrayLength(GetEnv(), exclusionListValue);
348         for (uint32_t index = 0; index < listLength; ++index) {
349             napi_value exclusionValue = NapiUtils::GetArrayElement(GetEnv(), exclusionListValue, index);
350             std::string exclusion = NapiUtils::GetStringFromValueUtf8(GetEnv(), exclusionValue);
351             if (index != 0) {
352                 exclusionList = exclusionList + HttpConstant::HTTP_PROXY_EXCLUSIONS_SEPARATOR;
353             }
354             exclusionList += exclusion;
355         }
356     }
357     options.SetSpecifiedHttpProxy(host, port, exclusionList);
358     options.SetUsingHttpProxyType(UsingHttpProxyType::USE_SPECIFIED);
359 }
360 
GetRequestBody(napi_value extraData)361 bool RequestContext::GetRequestBody(napi_value extraData)
362 {
363     /* if body is empty, return false, or curl will wait for body */
364 
365     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
366     if (type == napi_string) {
367         auto body = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
368         if (body.empty()) {
369             return false;
370         }
371         options.SetBody(body.c_str(), body.size());
372         return true;
373     }
374 
375     if (NapiUtils::ValueIsArrayBuffer(GetEnv(), extraData)) {
376         size_t length = 0;
377         void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), extraData, &length);
378         if (data == nullptr) {
379             return false;
380         }
381         options.SetBody(data, length);
382         return true;
383     }
384 
385     if (type == napi_object) {
386         std::string body = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), extraData));
387         if (body.empty()) {
388             return false;
389         }
390         options.SetBody(body.c_str(), body.length());
391         return true;
392     }
393 
394     NETSTACK_LOGE("only support string arraybuffer and object");
395     return false;
396 }
397 
ParseCaPath(napi_value optionsValue)398 void RequestContext::ParseCaPath(napi_value optionsValue)
399 {
400     std::string caPath = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CA_PATH);
401     if (!caPath.empty()) {
402         options.SetCaPath(caPath);
403     }
404 }
405 
ParseDohUrl(napi_value optionsValue)406 void RequestContext::ParseDohUrl(napi_value optionsValue)
407 {
408     std::string dohUrl = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_DOH_URL);
409     if (!dohUrl.empty()) {
410         options.SetDohUrl(dohUrl);
411     }
412 }
413 
ParseResumeFromToNumber(napi_value optionsValue)414 void RequestContext::ParseResumeFromToNumber(napi_value optionsValue)
415 {
416     napi_env env = GetEnv();
417     int64_t from = NapiUtils::GetInt64Property(env, optionsValue, HttpConstant::PARAM_KEY_RESUME_FROM);
418     int64_t to = NapiUtils::GetInt64Property(env, optionsValue, HttpConstant::PARAM_KEY_RESUME_TO);
419     options.SetRangeNumber(from, to);
420 }
421 
UrlAndOptions(napi_value urlValue,napi_value optionsValue)422 void RequestContext::UrlAndOptions(napi_value urlValue, napi_value optionsValue)
423 {
424     options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), urlValue));
425 
426     if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD)) {
427         napi_value requestMethod = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD);
428         if (NapiUtils::GetValueType(GetEnv(), requestMethod) == napi_string) {
429             options.SetMethod(NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD));
430         }
431     }
432 
433     ParseNumberOptions(optionsValue);
434     ParseUsingHttpProxy(optionsValue);
435     ParseClientCert(optionsValue);
436 
437     /* parse extra data here to recover header */
438     if (!ParseExtraData(optionsValue)) {
439         return;
440     }
441 
442     ParseHeader(optionsValue);
443     ParseCaPath(optionsValue);
444     ParseDohUrl(optionsValue);
445     ParseResumeFromToNumber(optionsValue);
446     ParseDnsServers(optionsValue);
447     ParseMultiFormData(optionsValue);
448     ParseCertificatePinning(optionsValue);
449     SetParseOK(true);
450     ParseAddressFamily(optionsValue);
451 }
452 
IsUsingCache() const453 bool RequestContext::IsUsingCache() const
454 {
455     return usingCache_;
456 }
457 
SetCurlHeaderList(curl_slist * curlHeaderList)458 void RequestContext::SetCurlHeaderList(curl_slist *curlHeaderList)
459 {
460     curlHeaderList_ = curlHeaderList;
461 }
462 
GetCurlHeaderList()463 curl_slist *RequestContext::GetCurlHeaderList()
464 {
465     return curlHeaderList_;
466 }
467 
SetCurlHostList(curl_slist * curlHostList)468 void RequestContext::SetCurlHostList(curl_slist *curlHostList)
469 {
470     curlHostList_ = curlHostList;
471 }
472 
GetCurlHostList()473 curl_slist *RequestContext::GetCurlHostList()
474 {
475     return curlHostList_;
476 }
477 
~RequestContext()478 RequestContext::~RequestContext()
479 {
480     if (curlHeaderList_ != nullptr) {
481         curl_slist_free_all(curlHeaderList_);
482     }
483     if (curlHostList_ != nullptr) {
484         curl_slist_free_all(curlHostList_);
485     }
486     if (multipart_ != nullptr) {
487         curl_mime_free(multipart_);
488         multipart_ = nullptr;
489     }
490     NETSTACK_LOGD("the destructor of request context is invoked");
491 }
492 
SetCacheResponse(const HttpResponse & cacheResponse)493 void RequestContext::SetCacheResponse(const HttpResponse &cacheResponse)
494 {
495     cacheResponse_ = cacheResponse;
496 }
SetResponseByCache()497 void RequestContext::SetResponseByCache()
498 {
499     response = cacheResponse_;
500 }
501 
GetErrorCode() const502 int32_t RequestContext::GetErrorCode() const
503 {
504     auto err = BaseContext::GetErrorCode();
505     if (err == PARSE_ERROR_CODE) {
506         return PARSE_ERROR_CODE;
507     }
508 
509     if (BaseContext::IsPermissionDenied()) {
510         return PERMISSION_DENIED_CODE;
511     }
512 
513     if (BaseContext::IsNoAllowedHost()) {
514         return HTTP_NOT_ALLOWED_HOST;
515     }
516 
517     if (HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE) != HTTP_ERR_MAP.end()) {
518         return err + HTTP_ERROR_CODE_BASE;
519     }
520     return HTTP_UNKNOWN_OTHER_ERROR;
521 }
522 
GetErrorMessage() const523 std::string RequestContext::GetErrorMessage() const
524 {
525     auto err = BaseContext::GetErrorCode();
526     if (err == PARSE_ERROR_CODE) {
527         return PARSE_ERROR_MSG;
528     }
529 
530     if (BaseContext::IsPermissionDenied()) {
531         return PERMISSION_DENIED_MSG;
532     }
533 
534     if (BaseContext::IsNoAllowedHost()) {
535         return HTTP_ERR_MAP.at(HTTP_NOT_ALLOWED_HOST);
536     }
537 
538     auto pos = HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE);
539     if (pos != HTTP_ERR_MAP.end()) {
540         return pos->second;
541     }
542     return HTTP_ERR_MAP.at(HTTP_UNKNOWN_OTHER_ERROR);
543 }
544 
EnableRequestInStream()545 void RequestContext::EnableRequestInStream()
546 {
547     requestInStream_ = true;
548 }
549 
IsRequestInStream() const550 bool RequestContext::IsRequestInStream() const
551 {
552     return requestInStream_;
553 }
554 
SetDlLen(curl_off_t nowLen,curl_off_t totalLen)555 void RequestContext::SetDlLen(curl_off_t nowLen, curl_off_t totalLen)
556 {
557     std::lock_guard<std::mutex> lock(dlLenLock_);
558     LoadBytes dlBytes{nowLen, totalLen};
559     dlBytes_.push(dlBytes);
560 }
561 
SetCertsPath(std::vector<std::string> && certPathList,const std::string & certFile)562 void RequestContext::SetCertsPath(std::vector<std::string> &&certPathList, const std::string &certFile)
563 {
564     certsPath_.certPathList = std::move(certPathList);
565     certsPath_.certFile = certFile;
566 }
567 
GetCertsPath()568 const CertsPath &RequestContext::GetCertsPath()
569 {
570     return certsPath_;
571 }
572 
GetDlLen()573 LoadBytes RequestContext::GetDlLen()
574 {
575     std::lock_guard<std::mutex> lock(dlLenLock_);
576     LoadBytes dlBytes;
577     if (!dlBytes_.empty()) {
578         dlBytes.nLen = dlBytes_.front().nLen;
579         dlBytes.tLen = dlBytes_.front().tLen;
580         dlBytes_.pop();
581     }
582     return dlBytes;
583 }
584 
SetUlLen(curl_off_t nowLen,curl_off_t totalLen)585 void RequestContext::SetUlLen(curl_off_t nowLen, curl_off_t totalLen)
586 {
587     std::lock_guard<std::mutex> lock(ulLenLock_);
588     if (!ulBytes_.empty()) {
589         ulBytes_.pop();
590     }
591     LoadBytes ulBytes{nowLen, totalLen};
592     ulBytes_.push(ulBytes);
593 }
594 
GetUlLen()595 LoadBytes RequestContext::GetUlLen()
596 {
597     std::lock_guard<std::mutex> lock(ulLenLock_);
598     LoadBytes ulBytes;
599     if (!ulBytes_.empty()) {
600         ulBytes.nLen = ulBytes_.back().nLen;
601         ulBytes.tLen = ulBytes_.back().tLen;
602     }
603     return ulBytes;
604 }
605 
CompareWithLastElement(curl_off_t nowLen,curl_off_t totalLen)606 bool RequestContext::CompareWithLastElement(curl_off_t nowLen, curl_off_t totalLen)
607 {
608     std::lock_guard<std::mutex> lock(ulLenLock_);
609     if (ulBytes_.empty()) {
610         return false;
611     }
612     const LoadBytes &lastElement = ulBytes_.back();
613     return nowLen == lastElement.nLen && totalLen == lastElement.tLen;
614 }
615 
SetTempData(const void * data,size_t size)616 void RequestContext::SetTempData(const void *data, size_t size)
617 {
618     std::lock_guard<std::mutex> lock(tempDataLock_);
619     std::string tempString;
620     tempString.append(reinterpret_cast<const char *>(data), size);
621     tempData_.push(tempString);
622 }
623 
GetTempData()624 std::string RequestContext::GetTempData()
625 {
626     std::lock_guard<std::mutex> lock(tempDataLock_);
627     if (!tempData_.empty()) {
628         return tempData_.front();
629     }
630     return {};
631 }
632 
PopTempData()633 void RequestContext::PopTempData()
634 {
635     std::lock_guard<std::mutex> lock(tempDataLock_);
636     if (!tempData_.empty()) {
637         tempData_.pop();
638     }
639 }
640 
ParseDnsServers(napi_value optionsValue)641 void RequestContext::ParseDnsServers(napi_value optionsValue)
642 {
643     napi_env env = GetEnv();
644     if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_DNS_SERVERS)) {
645         NETSTACK_LOGD("ParseDnsServers no data");
646         return;
647     }
648     napi_value dnsServerValue = NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_DNS_SERVERS);
649     if (NapiUtils::GetValueType(env, dnsServerValue) != napi_object) {
650         return;
651     }
652     uint32_t dnsLength = NapiUtils::GetArrayLength(env, dnsServerValue);
653     if (dnsLength == 0) {
654         return;
655     }
656     std::vector<std::string> dnsServers;
657     uint32_t dnsSize = 0;
658     for (uint32_t i = 0; i < dnsLength && dnsSize < DNS_SERVER_SIZE; i++) {
659         napi_value element = NapiUtils::GetArrayElement(env, dnsServerValue, i);
660         std::string dnsServer = NapiUtils::GetStringFromValueUtf8(env, element);
661         if (dnsServer.length() == 0) {
662             continue;
663         }
664         if (!CommonUtils::IsValidIPV4(dnsServer) && !CommonUtils::IsValidIPV6(dnsServer)) {
665             continue;
666         }
667         dnsServers.push_back(dnsServer);
668         dnsSize++;
669     }
670     if (dnsSize == 0 || dnsServers.data() == nullptr || dnsServers.empty()) {
671         NETSTACK_LOGD("dnsServersArray is empty.");
672         return;
673     }
674     options.SetDnsServers(dnsServers);
675     NETSTACK_LOGD("SetDnsServers success");
676 }
677 
CachePerformanceTimingItem(const std::string & key,double value)678 void RequestContext::CachePerformanceTimingItem(const std::string &key, double value)
679 {
680     performanceTimingMap_[key] = value;
681 }
682 
StopAndCacheNapiPerformanceTiming(const char * key)683 void RequestContext::StopAndCacheNapiPerformanceTiming(const char *key)
684 {
685     Timing::Timer &timer = timerMap_.RecieveTimer(key);
686     timer.Stop();
687     CachePerformanceTimingItem(key, timer.Elapsed());
688 }
689 
SetPerformanceTimingToResult(napi_value result)690 void RequestContext::SetPerformanceTimingToResult(napi_value result)
691 {
692     if (performanceTimingMap_.empty()) {
693         NETSTACK_LOGD("Get performanceTiming data is empty.");
694         return;
695     }
696     napi_value performanceTimingValue;
697     napi_env env = GetEnv();
698     napi_create_object(env, &performanceTimingValue);
699     for (const auto &pair : performanceTimingMap_) {
700         NapiUtils::SetDoubleProperty(env, performanceTimingValue, pair.first, pair.second);
701     }
702     NapiUtils::SetNamedProperty(env, result, HttpConstant::RESPONSE_PERFORMANCE_TIMING, performanceTimingValue);
703 }
704 
ParseClientCert(napi_value optionsValue)705 void RequestContext::ParseClientCert(napi_value optionsValue)
706 {
707     if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CLIENT_CERT)) {
708         return;
709     }
710     napi_value clientCertValue =
711         NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CLIENT_CERT);
712     napi_valuetype type = NapiUtils::GetValueType(GetEnv(), clientCertValue);
713     if (type != napi_object) {
714         return;
715     }
716     std::string cert = NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_CERT);
717     std::string certType =
718         NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_CERT_TYPE);
719     std::string key = NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_KEY);
720     Secure::SecureChar keyPasswd = Secure::SecureChar(
721         NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_KEY_PASSWD));
722     options.SetClientCert(cert, certType, key, keyPasswd);
723 }
724 
ParseMultiFormData(napi_value optionsValue)725 void RequestContext::ParseMultiFormData(napi_value optionsValue)
726 {
727     napi_env env = GetEnv();
728     if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST)) {
729         NETSTACK_LOGD("ParseMultiFormData multiFormDataList is null.");
730         return;
731     }
732     napi_value multiFormDataListValue =
733         NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST);
734     if (NapiUtils::GetValueType(env, multiFormDataListValue) != napi_object) {
735         NETSTACK_LOGE("ParseMultiFormData multiFormDataList type is not object.");
736         return;
737     }
738     uint32_t dataLength = NapiUtils::GetArrayLength(env, multiFormDataListValue);
739     if (dataLength == 0) {
740         NETSTACK_LOGD("ParseMultiFormData multiFormDataList length is 0.");
741         return;
742     }
743     for (uint32_t i = 0; i < dataLength; i++) {
744         napi_value formDataValue = NapiUtils::GetArrayElement(env, multiFormDataListValue, i);
745         MultiFormData multiFormData = NapiValue2FormData(formDataValue);
746         options.AddMultiFormData(multiFormData);
747     }
748 }
749 
NapiValue2FormData(napi_value formDataValue)750 MultiFormData RequestContext::NapiValue2FormData(napi_value formDataValue)
751 {
752     napi_env env = GetEnv();
753     MultiFormData multiFormData;
754     multiFormData.name = NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_NAME);
755     multiFormData.contentType =
756         NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_CONTENT_TYPE);
757     multiFormData.remoteFileName =
758         NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_REMOTE_FILE_NAME);
759     RequestContext::SaveFormData(
760         env, NapiUtils::GetNamedProperty(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_DATA), multiFormData);
761     multiFormData.filePath =
762         NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_FILE_PATH);
763     return multiFormData;
764 }
765 
NapiValue2CertPinning(napi_value certPIN)766 CertificatePinning RequestContext::NapiValue2CertPinning(napi_value certPIN)
767 {
768     napi_env env = GetEnv();
769     CertificatePinning singleCertPIN;
770     auto algorithm = NapiUtils::GetStringPropertyUtf8(env, certPIN, HttpConstant::HTTP_HASH_ALGORITHM);
771     if (algorithm == "SHA-256") {
772         singleCertPIN.hashAlgorithm = HashAlgorithm::SHA256;
773     } else {
774         singleCertPIN.hashAlgorithm = HashAlgorithm::INVALID;
775     }
776 
777     singleCertPIN.publicKeyHash = NapiUtils::GetStringPropertyUtf8(env, certPIN, HttpConstant::HTTP_PUBLIC_KEY_HASH);
778     return singleCertPIN;
779 }
780 
SaveFormData(napi_env env,napi_value dataValue,MultiFormData & multiFormData)781 void RequestContext::SaveFormData(napi_env env, napi_value dataValue, MultiFormData &multiFormData)
782 {
783     napi_valuetype type = NapiUtils::GetValueType(env, dataValue);
784     if (type == napi_string) {
785         multiFormData.data = NapiUtils::GetStringFromValueUtf8(GetEnv(), dataValue);
786         NETSTACK_LOGD("SaveFormData string");
787     } else if (NapiUtils::ValueIsArrayBuffer(GetEnv(), dataValue)) {
788         size_t length = 0;
789         void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), dataValue, &length);
790         if (data == nullptr) {
791             return;
792         }
793         multiFormData.data = std::string(static_cast<const char *>(data), length);
794         NETSTACK_LOGD("SaveFormData ArrayBuffer");
795     } else if (type == napi_object) {
796         multiFormData.data = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), dataValue));
797         NETSTACK_LOGD("SaveFormData Object");
798     } else {
799         NETSTACK_LOGD("only support string, ArrayBuffer and Object");
800     }
801 }
802 
ParseCertificatePinning(napi_value optionsValue)803 void RequestContext::ParseCertificatePinning(napi_value optionsValue)
804 {
805     auto env = GetEnv();
806     if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_CERTIFICATE_PINNING)) {
807         NETSTACK_LOGD("NO CertificatePinning option");
808         return;
809     }
810     napi_value certificatePin =
811         NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_CERTIFICATE_PINNING);
812     std::stringstream certPinBuilder;
813 
814     if (NapiUtils::IsArray(env, certificatePin)) {
815         auto arrayLen = NapiUtils::GetArrayLength(env, certificatePin);
816         for (uint32_t i = 0; i < arrayLen; i++) {
817             napi_value certPIN = NapiUtils::GetArrayElement(env, certificatePin, i);
818             CertificatePinning singleCertPIN = NapiValue2CertPinning(certPIN);
819             if (singleCertPIN.hashAlgorithm == HashAlgorithm::SHA256) {
820                 certPinBuilder << "sha256//" << singleCertPIN.publicKeyHash << ';';
821             }
822         }
823     } else {
824         CertificatePinning singleCertPIN = NapiValue2CertPinning(certificatePin);
825         if (singleCertPIN.hashAlgorithm == HashAlgorithm::SHA256) {
826             certPinBuilder << "sha256//" << singleCertPIN.publicKeyHash << ';';
827         }
828     }
829 
830     std::string pinRes = certPinBuilder.str();
831     if (!pinRes.empty()) {
832         pinRes.pop_back();
833         options.SetCertificatePinning(pinRes);
834     }
835 }
836 
SetMultipart(curl_mime * multipart)837 void RequestContext::SetMultipart(curl_mime *multipart)
838 {
839     multipart_ = multipart;
840 }
841 
GetTaskId() const842 int32_t RequestContext::GetTaskId() const
843 {
844     return taskId_;
845 }
846 
SetModuleId(uint64_t moduleId)847 void RequestContext::SetModuleId(uint64_t moduleId)
848 {
849     moduleId_ = moduleId;
850 }
851 
GetModuleId() const852 uint64_t RequestContext::GetModuleId() const
853 {
854     return moduleId_;
855 }
856 
IsAtomicService() const857 bool RequestContext::IsAtomicService() const
858 {
859     return isAtomicService_;
860 }
861 
SetAtomicService(bool isAtomicService)862 void RequestContext::SetAtomicService(bool isAtomicService)
863 {
864     isAtomicService_ = isAtomicService;
865 }
866 
SetBundleName(const std::string & bundleName)867 void RequestContext::SetBundleName(const std::string &bundleName)
868 {
869     bundleName_ = bundleName;
870 }
871 
GetBundleName() const872 std::string RequestContext::GetBundleName() const
873 {
874     return bundleName_;
875 }
876 
SetTraceName(const std::string & traceName)877 void RequestContext::SetTraceName(const std::string &traceName)
878 {
879     traceName_ = traceName;
880 }
881 
GetTraceName() const882 std::string RequestContext::GetTraceName() const
883 {
884     return traceName_;
885 }
886 
SetCurlHandle(CURL * handle)887 void RequestContext::SetCurlHandle(CURL *handle)
888 {
889     curlHandle_ = handle;
890 }
891 
SendNetworkProfiler()892 void RequestContext::SendNetworkProfiler()
893 {
894 #if HAS_NETMANAGER_BASE
895     HttpNetworkMessage networkMessage(std::to_string(GetTaskId()), options, response, curlHandle_);
896     networkProfilerUtils_->NetworkProfiling(networkMessage);
897 #endif
898 }
899 
IsRootCaVerified() const900 bool RequestContext::IsRootCaVerified() const
901 {
902     return isRootCaVerified_;
903 }
904 
SetRootCaVerified()905 void RequestContext::SetRootCaVerified()
906 {
907     isRootCaVerified_ = true;
908 }
909 
IsRootCaVerifiedOk() const910 bool RequestContext::IsRootCaVerifiedOk() const
911 {
912     return isRootCaVerifiedOk_;
913 }
914 
SetRootCaVerifiedOk(bool ok)915 void RequestContext::SetRootCaVerifiedOk(bool ok)
916 {
917     isRootCaVerifiedOk_ = ok;
918 }
919 
SetPinnedPubkey(std::string & pubkey)920 void RequestContext::SetPinnedPubkey(std::string &pubkey)
921 {
922     pinnedPubkey_ = pubkey;
923 }
924 
GetPinnedPubkey() const925 std::string RequestContext::GetPinnedPubkey() const
926 {
927     return pinnedPubkey_;
928 }
929 
ParseAddressFamily(napi_value optionsValue)930 void RequestContext::ParseAddressFamily(napi_value optionsValue)
931 {
932     std::string addressFamily = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue,
933         HttpConstant::PARAM_KEY_ADDRESS_FAMILY);
934     if (!addressFamily.empty()) {
935         options.SetAddressFamily(addressFamily);
936     }
937 }
938 } // namespace OHOS::NetStack::Http
939