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
ParseParams(napi_value * params,size_t paramsCount)104 void RequestContext::ParseParams(napi_value *params, size_t paramsCount)
105 {
106 bool valid = CheckParamsType(params, paramsCount);
107 if (!valid) {
108 if (paramsCount == PARAM_JUST_URL_OR_CALLBACK) {
109 if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) {
110 SetCallback(params[0]);
111 }
112 return;
113 }
114 if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
115 if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) {
116 SetCallback(params[1]);
117 }
118 return;
119 }
120 if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
121 if (NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function) {
122 SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]);
123 }
124 return;
125 }
126 return;
127 }
128
129 if (paramsCount == PARAM_JUST_URL) {
130 options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
131 SetParseOK(true);
132 return;
133 }
134
135 if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
136 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
137 if (type == napi_function) {
138 options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
139 SetParseOK(SetCallback(params[1]) == napi_ok);
140 return;
141 }
142 if (type == napi_object) {
143 UrlAndOptions(params[0], params[1]);
144 return;
145 }
146 return;
147 }
148
149 if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
150 if (SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) != napi_ok) {
151 return;
152 }
153 UrlAndOptions(params[0], params[1]);
154 }
155 }
156
CheckParamsType(napi_value * params,size_t paramsCount)157 bool RequestContext::CheckParamsType(napi_value *params, size_t paramsCount)
158 {
159 if (paramsCount == PARAM_JUST_URL) {
160 // just url
161 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string;
162 }
163 if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
164 // should be url, callback or url, options
165 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
166 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
167 (type == napi_function || type == napi_object);
168 }
169 if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
170 // should be url options and callback
171 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
172 NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object &&
173 NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function;
174 }
175 return false;
176 }
177
ParseNumberOptions(napi_value optionsValue)178 void RequestContext::ParseNumberOptions(napi_value optionsValue)
179 {
180 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT)) {
181 options.SetReadTimeout(
182 NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT));
183 }
184
185 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_MAX_LIMIT)) {
186 options.SetMaxLimit(NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_MAX_LIMIT));
187 }
188
189 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT)) {
190 options.SetConnectTimeout(
191 NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT));
192 }
193
194 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_CACHE)) {
195 napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_CACHE);
196 if (NapiUtils::GetValueType(GetEnv(), value) == napi_boolean) {
197 usingCache_ = NapiUtils::GetBooleanFromValue(GetEnv(), value);
198 }
199 }
200
201 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_PROTOCOL)) {
202 napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_PROTOCOL);
203 if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
204 uint32_t number = NapiUtils::GetUint32FromValue(GetEnv(), value);
205 if (number == static_cast<uint32_t>(HttpProtocol::HTTP1_1) ||
206 number == static_cast<uint32_t>(HttpProtocol::HTTP2) ||
207 number == static_cast<uint32_t>(HttpProtocol::HTTP3)) {
208 options.SetUsingProtocol(static_cast<HttpProtocol>(number));
209 }
210 }
211 }
212 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXPECT_DATA_TYPE)) {
213 napi_value value =
214 NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXPECT_DATA_TYPE);
215 if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
216 uint32_t type = NapiUtils::GetUint32FromValue(GetEnv(), value);
217 options.SetHttpDataType(static_cast<HttpDataType>(type));
218 }
219 }
220
221 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_PRIORITY)) {
222 napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_PRIORITY);
223 if (NapiUtils::GetValueType(GetEnv(), value) == napi_number) {
224 uint32_t priority = NapiUtils::GetUint32FromValue(GetEnv(), value);
225 options.SetPriority(priority);
226 }
227 }
228 }
229
ParseHeader(napi_value optionsValue)230 void RequestContext::ParseHeader(napi_value optionsValue)
231 {
232 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER)) {
233 return;
234 }
235 napi_value header = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER);
236 if (NapiUtils::GetValueType(GetEnv(), header) != napi_object) {
237 return;
238 }
239 if (HttpExec::MethodForPost(options.GetMethod())) {
240 options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
241 HttpConstant::HTTP_CONTENT_TYPE_JSON); // default
242 }
243 auto names = NapiUtils::GetPropertyNames(GetEnv(), header);
244 std::for_each(names.begin(), names.end(), [header, this](const std::string &name) {
245 napi_value value = NapiUtils::GetNamedProperty(GetEnv(), header, name);
246 std::string valueStr = NapiUtils::NapiValueToString(GetEnv(), value);
247 options.SetHeader(CommonUtils::ToLower(name), valueStr);
248 });
249 }
250
HandleMethodForGet(napi_value extraData)251 bool RequestContext::HandleMethodForGet(napi_value extraData)
252 {
253 std::string url = options.GetUrl();
254 std::string param;
255 auto index = url.find(HttpConstant::HTTP_URL_PARAM_START);
256 if (index != std::string::npos) {
257 param = url.substr(index + 1);
258 url.resize(index);
259 }
260
261 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
262 if (type == napi_string) {
263 std::string extraParam = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
264
265 options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
266 return true;
267 }
268 if (type != napi_object) {
269 return true;
270 }
271
272 std::string extraParam;
273 auto names = NapiUtils::GetPropertyNames(GetEnv(), extraData);
274 std::for_each(names.begin(), names.end(), [this, extraData, &extraParam](std::string name) {
275 auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), extraData, name);
276 if (!name.empty() && !value.empty()) {
277 bool encodeName = HttpExec::EncodeUrlParam(name);
278 bool encodeValue = HttpExec::EncodeUrlParam(value);
279 if (encodeName || encodeValue) {
280 options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
281 HttpConstant::HTTP_CONTENT_TYPE_URL_ENCODE);
282 }
283 extraParam +=
284 name + HttpConstant::HTTP_URL_NAME_VALUE_SEPARATOR + value + HttpConstant::HTTP_URL_PARAM_SEPARATOR;
285 }
286 });
287 if (!extraParam.empty()) {
288 extraParam.pop_back(); // remove the last &
289 }
290
291 options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
292 return true;
293 }
294
ParseExtraData(napi_value optionsValue)295 bool RequestContext::ParseExtraData(napi_value optionsValue)
296 {
297 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA)) {
298 NETSTACK_LOGD("no extraData");
299 return true;
300 }
301
302 napi_value extraData = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA);
303 if (NapiUtils::GetValueType(GetEnv(), extraData) == napi_undefined ||
304 NapiUtils::GetValueType(GetEnv(), extraData) == napi_null) {
305 NETSTACK_LOGD("extraData is undefined or null");
306 return true;
307 }
308
309 if (HttpExec::MethodForGet(options.GetMethod())) {
310 return HandleMethodForGet(extraData);
311 }
312
313 if (HttpExec::MethodForPost(options.GetMethod())) {
314 return GetRequestBody(extraData);
315 }
316 return false;
317 }
318
ParseUsingHttpProxy(napi_value optionsValue)319 void RequestContext::ParseUsingHttpProxy(napi_value optionsValue)
320 {
321 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_HTTP_PROXY)) {
322 NETSTACK_LOGD("Use default proxy");
323 return;
324 }
325 napi_value httpProxyValue =
326 NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_USING_HTTP_PROXY);
327 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), httpProxyValue);
328 if (type == napi_boolean) {
329 bool usingProxy = NapiUtils::GetBooleanFromValue(GetEnv(), httpProxyValue);
330 UsingHttpProxyType usingType = usingProxy ? UsingHttpProxyType::USE_DEFAULT : UsingHttpProxyType::NOT_USE;
331 options.SetUsingHttpProxyType(usingType);
332 return;
333 }
334 if (type != napi_object) {
335 return;
336 }
337 std::string host = NapiUtils::GetStringPropertyUtf8(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_HOST);
338 int32_t port = NapiUtils::GetInt32Property(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_PORT);
339 std::string exclusionList;
340 if (NapiUtils::HasNamedProperty(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST)) {
341 napi_value exclusionListValue =
342 NapiUtils::GetNamedProperty(GetEnv(), httpProxyValue, HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST);
343 uint32_t listLength = NapiUtils::GetArrayLength(GetEnv(), exclusionListValue);
344 for (uint32_t index = 0; index < listLength; ++index) {
345 napi_value exclusionValue = NapiUtils::GetArrayElement(GetEnv(), exclusionListValue, index);
346 std::string exclusion = NapiUtils::GetStringFromValueUtf8(GetEnv(), exclusionValue);
347 if (index != 0) {
348 exclusionList = exclusionList + HttpConstant::HTTP_PROXY_EXCLUSIONS_SEPARATOR;
349 }
350 exclusionList += exclusion;
351 }
352 }
353 options.SetSpecifiedHttpProxy(host, port, exclusionList);
354 options.SetUsingHttpProxyType(UsingHttpProxyType::USE_SPECIFIED);
355 }
356
GetRequestBody(napi_value extraData)357 bool RequestContext::GetRequestBody(napi_value extraData)
358 {
359 /* if body is empty, return false, or curl will wait for body */
360
361 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
362 if (type == napi_string) {
363 auto body = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
364 if (body.empty()) {
365 return false;
366 }
367 options.SetBody(body.c_str(), body.size());
368 return true;
369 }
370
371 if (NapiUtils::ValueIsArrayBuffer(GetEnv(), extraData)) {
372 size_t length = 0;
373 void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), extraData, &length);
374 if (data == nullptr) {
375 return false;
376 }
377 options.SetBody(data, length);
378 return true;
379 }
380
381 if (type == napi_object) {
382 std::string body = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), extraData));
383 if (body.empty()) {
384 return false;
385 }
386 options.SetBody(body.c_str(), body.length());
387 return true;
388 }
389
390 NETSTACK_LOGE("only support string arraybuffer and object");
391 return false;
392 }
393
ParseCaPath(napi_value optionsValue)394 void RequestContext::ParseCaPath(napi_value optionsValue)
395 {
396 std::string caPath = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CA_PATH);
397 if (!caPath.empty()) {
398 options.SetCaPath(caPath);
399 }
400 }
401
ParseDohUrl(napi_value optionsValue)402 void RequestContext::ParseDohUrl(napi_value optionsValue)
403 {
404 std::string dohUrl = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_DOH_URL);
405 if (!dohUrl.empty()) {
406 options.SetDohUrl(dohUrl);
407 }
408 }
409
ParseResumeFromToNumber(napi_value optionsValue)410 void RequestContext::ParseResumeFromToNumber(napi_value optionsValue)
411 {
412 napi_env env = GetEnv();
413 int64_t from = NapiUtils::GetInt64Property(env, optionsValue, HttpConstant::PARAM_KEY_RESUME_FROM);
414 int64_t to = NapiUtils::GetInt64Property(env, optionsValue, HttpConstant::PARAM_KEY_RESUME_TO);
415 options.SetRangeNumber(from, to);
416 }
417
UrlAndOptions(napi_value urlValue,napi_value optionsValue)418 void RequestContext::UrlAndOptions(napi_value urlValue, napi_value optionsValue)
419 {
420 options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), urlValue));
421
422 if (NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD)) {
423 napi_value requestMethod = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD);
424 if (NapiUtils::GetValueType(GetEnv(), requestMethod) == napi_string) {
425 options.SetMethod(NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD));
426 }
427 }
428
429 ParseNumberOptions(optionsValue);
430 ParseUsingHttpProxy(optionsValue);
431 ParseClientCert(optionsValue);
432
433 /* parse extra data here to recover header */
434 if (!ParseExtraData(optionsValue)) {
435 return;
436 }
437
438 ParseHeader(optionsValue);
439 ParseCaPath(optionsValue);
440 ParseDohUrl(optionsValue);
441 ParseResumeFromToNumber(optionsValue);
442 ParseDnsServers(optionsValue);
443 ParseMultiFormData(optionsValue);
444 ParseCertificatePinning(optionsValue);
445 SetParseOK(true);
446 }
447
IsUsingCache() const448 bool RequestContext::IsUsingCache() const
449 {
450 return usingCache_;
451 }
452
SetCurlHeaderList(curl_slist * curlHeaderList)453 void RequestContext::SetCurlHeaderList(curl_slist *curlHeaderList)
454 {
455 curlHeaderList_ = curlHeaderList;
456 }
457
GetCurlHeaderList()458 curl_slist *RequestContext::GetCurlHeaderList()
459 {
460 return curlHeaderList_;
461 }
462
SetCurlHostList(curl_slist * curlHostList)463 void RequestContext::SetCurlHostList(curl_slist *curlHostList)
464 {
465 curlHostList_ = curlHostList;
466 }
467
GetCurlHostList()468 curl_slist *RequestContext::GetCurlHostList()
469 {
470 return curlHostList_;
471 }
472
~RequestContext()473 RequestContext::~RequestContext()
474 {
475 if (curlHeaderList_ != nullptr) {
476 curl_slist_free_all(curlHeaderList_);
477 }
478 if (curlHostList_ != nullptr) {
479 curl_slist_free_all(curlHostList_);
480 }
481 if (multipart_ != nullptr) {
482 curl_mime_free(multipart_);
483 multipart_ = nullptr;
484 }
485 NETSTACK_LOGD("the destructor of request context is invoked");
486 }
487
SetCacheResponse(const HttpResponse & cacheResponse)488 void RequestContext::SetCacheResponse(const HttpResponse &cacheResponse)
489 {
490 cacheResponse_ = cacheResponse;
491 }
SetResponseByCache()492 void RequestContext::SetResponseByCache()
493 {
494 response = cacheResponse_;
495 }
496
GetErrorCode() const497 int32_t RequestContext::GetErrorCode() const
498 {
499 auto err = BaseContext::GetErrorCode();
500 if (err == PARSE_ERROR_CODE) {
501 return PARSE_ERROR_CODE;
502 }
503
504 if (BaseContext::IsPermissionDenied()) {
505 return PERMISSION_DENIED_CODE;
506 }
507
508 if (BaseContext::IsNoAllowedHost()) {
509 return HTTP_NOT_ALLOWED_HOST;
510 }
511
512 if (HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE) != HTTP_ERR_MAP.end()) {
513 return err + HTTP_ERROR_CODE_BASE;
514 }
515 return HTTP_UNKNOWN_OTHER_ERROR;
516 }
517
GetErrorMessage() const518 std::string RequestContext::GetErrorMessage() const
519 {
520 auto err = BaseContext::GetErrorCode();
521 if (err == PARSE_ERROR_CODE) {
522 return PARSE_ERROR_MSG;
523 }
524
525 if (BaseContext::IsPermissionDenied()) {
526 return PERMISSION_DENIED_MSG;
527 }
528
529 if (BaseContext::IsNoAllowedHost()) {
530 return HTTP_ERR_MAP.at(HTTP_NOT_ALLOWED_HOST);
531 }
532
533 auto pos = HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE);
534 if (pos != HTTP_ERR_MAP.end()) {
535 return pos->second;
536 }
537 return HTTP_ERR_MAP.at(HTTP_UNKNOWN_OTHER_ERROR);
538 }
539
EnableRequestInStream()540 void RequestContext::EnableRequestInStream()
541 {
542 requestInStream_ = true;
543 }
544
IsRequestInStream() const545 bool RequestContext::IsRequestInStream() const
546 {
547 return requestInStream_;
548 }
549
SetDlLen(curl_off_t nowLen,curl_off_t totalLen)550 void RequestContext::SetDlLen(curl_off_t nowLen, curl_off_t totalLen)
551 {
552 std::lock_guard<std::mutex> lock(dlLenLock_);
553 LoadBytes dlBytes{nowLen, totalLen};
554 dlBytes_.push(dlBytes);
555 }
556
SetCertsPath(std::vector<std::string> && certPathList,const std::string & certFile)557 void RequestContext::SetCertsPath(std::vector<std::string> &&certPathList, const std::string &certFile)
558 {
559 certsPath_.certPathList = std::move(certPathList);
560 certsPath_.certFile = certFile;
561 }
562
GetCertsPath()563 const CertsPath &RequestContext::GetCertsPath()
564 {
565 return certsPath_;
566 }
567
GetDlLen()568 LoadBytes RequestContext::GetDlLen()
569 {
570 std::lock_guard<std::mutex> lock(dlLenLock_);
571 LoadBytes dlBytes;
572 if (!dlBytes_.empty()) {
573 dlBytes.nLen = dlBytes_.front().nLen;
574 dlBytes.tLen = dlBytes_.front().tLen;
575 dlBytes_.pop();
576 }
577 return dlBytes;
578 }
579
SetUlLen(curl_off_t nowLen,curl_off_t totalLen)580 void RequestContext::SetUlLen(curl_off_t nowLen, curl_off_t totalLen)
581 {
582 std::lock_guard<std::mutex> lock(ulLenLock_);
583 if (!ulBytes_.empty()) {
584 ulBytes_.pop();
585 }
586 LoadBytes ulBytes{nowLen, totalLen};
587 ulBytes_.push(ulBytes);
588 }
589
GetUlLen()590 LoadBytes RequestContext::GetUlLen()
591 {
592 std::lock_guard<std::mutex> lock(ulLenLock_);
593 LoadBytes ulBytes;
594 if (!ulBytes_.empty()) {
595 ulBytes.nLen = ulBytes_.back().nLen;
596 ulBytes.tLen = ulBytes_.back().tLen;
597 }
598 return ulBytes;
599 }
600
CompareWithLastElement(curl_off_t nowLen,curl_off_t totalLen)601 bool RequestContext::CompareWithLastElement(curl_off_t nowLen, curl_off_t totalLen)
602 {
603 std::lock_guard<std::mutex> lock(ulLenLock_);
604 if (ulBytes_.empty()) {
605 return false;
606 }
607 const LoadBytes &lastElement = ulBytes_.back();
608 return nowLen == lastElement.nLen && totalLen == lastElement.tLen;
609 }
610
SetTempData(const void * data,size_t size)611 void RequestContext::SetTempData(const void *data, size_t size)
612 {
613 std::lock_guard<std::mutex> lock(tempDataLock_);
614 std::string tempString;
615 tempString.append(reinterpret_cast<const char *>(data), size);
616 tempData_.push(tempString);
617 }
618
GetTempData()619 std::string RequestContext::GetTempData()
620 {
621 std::lock_guard<std::mutex> lock(tempDataLock_);
622 if (!tempData_.empty()) {
623 return tempData_.front();
624 }
625 return {};
626 }
627
PopTempData()628 void RequestContext::PopTempData()
629 {
630 std::lock_guard<std::mutex> lock(tempDataLock_);
631 if (!tempData_.empty()) {
632 tempData_.pop();
633 }
634 }
635
ParseDnsServers(napi_value optionsValue)636 void RequestContext::ParseDnsServers(napi_value optionsValue)
637 {
638 napi_env env = GetEnv();
639 if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_DNS_SERVERS)) {
640 NETSTACK_LOGD("ParseDnsServers no data");
641 return;
642 }
643 napi_value dnsServerValue = NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_DNS_SERVERS);
644 if (NapiUtils::GetValueType(env, dnsServerValue) != napi_object) {
645 return;
646 }
647 uint32_t dnsLength = NapiUtils::GetArrayLength(env, dnsServerValue);
648 if (dnsLength == 0) {
649 return;
650 }
651 std::vector<std::string> dnsServers;
652 uint32_t dnsSize = 0;
653 for (uint32_t i = 0; i < dnsLength && dnsSize < DNS_SERVER_SIZE; i++) {
654 napi_value element = NapiUtils::GetArrayElement(env, dnsServerValue, i);
655 std::string dnsServer = NapiUtils::GetStringFromValueUtf8(env, element);
656 if (dnsServer.length() == 0) {
657 continue;
658 }
659 if (!CommonUtils::IsValidIPV4(dnsServer) && !CommonUtils::IsValidIPV6(dnsServer)) {
660 continue;
661 }
662 dnsServers.push_back(dnsServer);
663 dnsSize++;
664 }
665 if (dnsSize == 0 || dnsServers.data() == nullptr || dnsServers.empty()) {
666 NETSTACK_LOGD("dnsServersArray is empty.");
667 return;
668 }
669 options.SetDnsServers(dnsServers);
670 NETSTACK_LOGD("SetDnsServers success");
671 }
672
CachePerformanceTimingItem(const std::string & key,double value)673 void RequestContext::CachePerformanceTimingItem(const std::string &key, double value)
674 {
675 performanceTimingMap_[key] = value;
676 }
677
StopAndCacheNapiPerformanceTiming(const char * key)678 void RequestContext::StopAndCacheNapiPerformanceTiming(const char *key)
679 {
680 Timing::Timer &timer = timerMap_.RecieveTimer(key);
681 timer.Stop();
682 CachePerformanceTimingItem(key, timer.Elapsed());
683 }
684
SetPerformanceTimingToResult(napi_value result)685 void RequestContext::SetPerformanceTimingToResult(napi_value result)
686 {
687 if (performanceTimingMap_.empty()) {
688 NETSTACK_LOGD("Get performanceTiming data is empty.");
689 return;
690 }
691 napi_value performanceTimingValue;
692 napi_env env = GetEnv();
693 napi_create_object(env, &performanceTimingValue);
694 for (const auto &pair : performanceTimingMap_) {
695 NapiUtils::SetDoubleProperty(env, performanceTimingValue, pair.first, pair.second);
696 }
697 NapiUtils::SetNamedProperty(env, result, HttpConstant::RESPONSE_PERFORMANCE_TIMING, performanceTimingValue);
698 }
699
ParseClientCert(napi_value optionsValue)700 void RequestContext::ParseClientCert(napi_value optionsValue)
701 {
702 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CLIENT_CERT)) {
703 return;
704 }
705 napi_value clientCertValue =
706 NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CLIENT_CERT);
707 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), clientCertValue);
708 if (type != napi_object) {
709 return;
710 }
711 std::string cert = NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_CERT);
712 std::string certType =
713 NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_CERT_TYPE);
714 std::string key = NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_KEY);
715 Secure::SecureChar keyPasswd = Secure::SecureChar(
716 NapiUtils::GetStringPropertyUtf8(GetEnv(), clientCertValue, HttpConstant::HTTP_CLIENT_KEY_PASSWD));
717 options.SetClientCert(cert, certType, key, keyPasswd);
718 }
719
ParseMultiFormData(napi_value optionsValue)720 void RequestContext::ParseMultiFormData(napi_value optionsValue)
721 {
722 napi_env env = GetEnv();
723 if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST)) {
724 NETSTACK_LOGD("ParseMultiFormData multiFormDataList is null.");
725 return;
726 }
727 napi_value multiFormDataListValue =
728 NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST);
729 if (NapiUtils::GetValueType(env, multiFormDataListValue) != napi_object) {
730 NETSTACK_LOGE("ParseMultiFormData multiFormDataList type is not object.");
731 return;
732 }
733 uint32_t dataLength = NapiUtils::GetArrayLength(env, multiFormDataListValue);
734 if (dataLength == 0) {
735 NETSTACK_LOGD("ParseMultiFormData multiFormDataList length is 0.");
736 return;
737 }
738 for (uint32_t i = 0; i < dataLength; i++) {
739 napi_value formDataValue = NapiUtils::GetArrayElement(env, multiFormDataListValue, i);
740 MultiFormData multiFormData = NapiValue2FormData(formDataValue);
741 options.AddMultiFormData(multiFormData);
742 }
743 }
744
NapiValue2FormData(napi_value formDataValue)745 MultiFormData RequestContext::NapiValue2FormData(napi_value formDataValue)
746 {
747 napi_env env = GetEnv();
748 MultiFormData multiFormData;
749 multiFormData.name = NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_NAME);
750 multiFormData.contentType =
751 NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_CONTENT_TYPE);
752 multiFormData.remoteFileName =
753 NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_REMOTE_FILE_NAME);
754 RequestContext::SaveFormData(
755 env, NapiUtils::GetNamedProperty(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_DATA), multiFormData);
756 multiFormData.filePath =
757 NapiUtils::GetStringPropertyUtf8(env, formDataValue, HttpConstant::HTTP_MULTI_FORM_DATA_FILE_PATH);
758 return multiFormData;
759 }
760
NapiValue2CertPinning(napi_value certPIN)761 CertificatePinning RequestContext::NapiValue2CertPinning(napi_value certPIN)
762 {
763 napi_env env = GetEnv();
764 CertificatePinning singleCertPIN;
765 auto algorithm = NapiUtils::GetStringPropertyUtf8(env, certPIN, HttpConstant::HTTP_HASH_ALGORITHM);
766 if (algorithm == "SHA-256") {
767 singleCertPIN.hashAlgorithm = HashAlgorithm::SHA256;
768 } else {
769 singleCertPIN.hashAlgorithm = HashAlgorithm::INVALID;
770 }
771
772 singleCertPIN.publicKeyHash = NapiUtils::GetStringPropertyUtf8(env, certPIN, HttpConstant::HTTP_PUBLIC_KEY_HASH);
773 return singleCertPIN;
774 }
775
SaveFormData(napi_env env,napi_value dataValue,MultiFormData & multiFormData)776 void RequestContext::SaveFormData(napi_env env, napi_value dataValue, MultiFormData &multiFormData)
777 {
778 napi_valuetype type = NapiUtils::GetValueType(env, dataValue);
779 if (type == napi_string) {
780 multiFormData.data = NapiUtils::GetStringFromValueUtf8(GetEnv(), dataValue);
781 NETSTACK_LOGD("SaveFormData string");
782 } else if (NapiUtils::ValueIsArrayBuffer(GetEnv(), dataValue)) {
783 size_t length = 0;
784 void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), dataValue, &length);
785 if (data == nullptr) {
786 return;
787 }
788 multiFormData.data = std::string(static_cast<const char *>(data), length);
789 NETSTACK_LOGD("SaveFormData ArrayBuffer");
790 } else if (type == napi_object) {
791 multiFormData.data = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), dataValue));
792 NETSTACK_LOGD("SaveFormData Object");
793 } else {
794 NETSTACK_LOGD("only support string, ArrayBuffer and Object");
795 }
796 }
797
ParseCertificatePinning(napi_value optionsValue)798 void RequestContext::ParseCertificatePinning(napi_value optionsValue)
799 {
800 auto env = GetEnv();
801 if (!NapiUtils::HasNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_CERTIFICATE_PINNING)) {
802 NETSTACK_LOGD("NO CertificatePinning option");
803 return;
804 }
805 napi_value certificatePin =
806 NapiUtils::GetNamedProperty(env, optionsValue, HttpConstant::PARAM_KEY_CERTIFICATE_PINNING);
807 std::stringstream certPinBuilder;
808
809 if (NapiUtils::IsArray(env, certificatePin)) {
810 auto arrayLen = NapiUtils::GetArrayLength(env, certificatePin);
811 for (uint32_t i = 0; i < arrayLen; i++) {
812 napi_value certPIN = NapiUtils::GetArrayElement(env, certificatePin, i);
813 CertificatePinning singleCertPIN = NapiValue2CertPinning(certPIN);
814 if (singleCertPIN.hashAlgorithm == HashAlgorithm::SHA256) {
815 certPinBuilder << "sha256//" << singleCertPIN.publicKeyHash << ';';
816 }
817 }
818 } else {
819 CertificatePinning singleCertPIN = NapiValue2CertPinning(certificatePin);
820 if (singleCertPIN.hashAlgorithm == HashAlgorithm::SHA256) {
821 certPinBuilder << "sha256//" << singleCertPIN.publicKeyHash << ';';
822 }
823 }
824
825 std::string pinRes = certPinBuilder.str();
826 if (!pinRes.empty()) {
827 pinRes.pop_back();
828 options.SetCertificatePinning(pinRes);
829 }
830 }
831
SetMultipart(curl_mime * multipart)832 void RequestContext::SetMultipart(curl_mime *multipart)
833 {
834 multipart_ = multipart;
835 }
836
GetTaskId() const837 int32_t RequestContext::GetTaskId() const
838 {
839 return taskId_;
840 }
841
SetModuleId(uint64_t moduleId)842 void RequestContext::SetModuleId(uint64_t moduleId)
843 {
844 moduleId_ = moduleId;
845 }
846
GetModuleId() const847 uint64_t RequestContext::GetModuleId() const
848 {
849 return moduleId_;
850 }
851
IsAtomicService() const852 bool RequestContext::IsAtomicService() const
853 {
854 return isAtomicService_;
855 }
856
SetAtomicService(bool isAtomicService)857 void RequestContext::SetAtomicService(bool isAtomicService)
858 {
859 isAtomicService_ = isAtomicService;
860 }
861
SetBundleName(const std::string & bundleName)862 void RequestContext::SetBundleName(const std::string &bundleName)
863 {
864 bundleName_ = bundleName;
865 }
866
GetBundleName() const867 std::string RequestContext::GetBundleName() const
868 {
869 return bundleName_;
870 }
871
SetTraceName(const std::string & traceName)872 void RequestContext::SetTraceName(const std::string &traceName)
873 {
874 traceName_ = traceName;
875 }
876
GetTraceName() const877 std::string RequestContext::GetTraceName() const
878 {
879 return traceName_;
880 }
881
SetCurlHandle(CURL * handle)882 void RequestContext::SetCurlHandle(CURL *handle)
883 {
884 curlHandle_ = handle;
885 }
886
SendNetworkProfiler()887 void RequestContext::SendNetworkProfiler()
888 {
889 #if HAS_NETMANAGER_BASE
890 HttpNetworkMessage networkMessage(std::to_string(GetTaskId()), options, response, curlHandle_);
891 networkProfilerUtils_->NetworkProfiling(networkMessage);
892 #endif
893 }
894 } // namespace OHOS::NetStack::Http
895