1 /*
2  * Copyright (c) 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 "net_http_request_context.h"
17 
18 #include <algorithm>
19 
20 #include "constant.h"
21 #include "net_http_client_exec.h"
22 #include "netstack_common_utils.h"
23 #include "netstack_log.h"
24 #include "net_http_utils.h"
25 
26 static constexpr const int32_t RESPONSE_MAX_SIZE = 1024 * 1024 * 1024;
27 static constexpr const uint32_t DNS_SERVER_SIZE = 3;
28 static constexpr const int32_t PROP_UNSET = -1;
29 static constexpr size_t PERMISSION_DENIED_CODE = 201;
30 static constexpr const char *PERMISSION_DENIED_MSG = "Permission denied";
31 namespace OHOS::NetStack::Http {
32 static const std::map<int32_t, const char *> HTTP_ERR_MAP = {
33     {static_cast<int32_t>(HttpErrorCode::HTTP_UNSUPPORTED_PROTOCOL), "Unsupported protocol."},
34     {static_cast<int32_t>(HttpErrorCode::HTTP_URL_MALFORMAT), "URL using bad/illegal format or missing URL."},
35     {static_cast<int32_t>(HttpErrorCode::HTTP_COULDNT_RESOLVE_PROXY), "Couldn't resolve proxy name."},
36     {static_cast<int32_t>(HttpErrorCode::HTTP_COULDNT_RESOLVE_HOST), "Couldn't resolve host name."},
37     {static_cast<int32_t>(HttpErrorCode::HTTP_COULDNT_CONNECT), "Couldn't connect to server."},
38     {static_cast<int32_t>(HttpErrorCode::HTTP_WEIRD_SERVER_REPLY), "Weird server reply."},
39     {static_cast<int32_t>(HttpErrorCode::HTTP_REMOTE_ACCESS_DENIED), "Access denied to remote resource."},
40     {static_cast<int32_t>(HttpErrorCode::HTTP_HTTP2_ERROR), "Error in the HTTP2 framing layer."},
41     {static_cast<int32_t>(HttpErrorCode::HTTP_PARTIAL_FILE), "Transferred a partial file."},
42     {static_cast<int32_t>(HttpErrorCode::HTTP_WRITE_ERROR), "Failed writing received data to disk/application."},
43     {static_cast<int32_t>(HttpErrorCode::HTTP_UPLOAD_FAILED), "Upload failed."},
44     {static_cast<int32_t>(HttpErrorCode::HTTP_READ_ERROR), "Failed to open/read local data from file/application."},
45     {static_cast<int32_t>(HttpErrorCode::HTTP_OUT_OF_MEMORY), "Out of memory."},
46     {static_cast<int32_t>(HttpErrorCode::HTTP_OPERATION_TIMEDOUT), "Timeout was reached."},
47     {static_cast<int32_t>(HttpErrorCode::HTTP_TOO_MANY_REDIRECTS), "Number of redirects hit maximum amount."},
48     {static_cast<int32_t>(HttpErrorCode::HTTP_GOT_NOTHING), "Server returned nothing (no headers, no data)."},
49     {static_cast<int32_t>(HttpErrorCode::HTTP_SEND_ERROR), "Failed sending data to the peer."},
50     {static_cast<int32_t>(HttpErrorCode::HTTP_RECV_ERROR), "Failure when receiving data from the peer."},
51     {static_cast<int32_t>(HttpErrorCode::HTTP_SSL_CERTPROBLEM), "Problem with the local SSL certificate."},
52     {static_cast<int32_t>(HttpErrorCode::HTTP_SSL_CIPHER), "Couldn't use specified SSL cipher."},
53     {static_cast<int32_t>(HttpErrorCode::HTTP_PEER_FAILED_VERIFICATION),
54         "SSL peer certificate or SSH remote key was not OK."},
55     {static_cast<int32_t>(HttpErrorCode::HTTP_BAD_CONTENT_ENCODING),
56         "Unrecognized or bad HTTP Content or Transfer-Encoding."},
57     {static_cast<int32_t>(HttpErrorCode::HTTP_FILESIZE_EXCEEDED), "Maximum file size exceeded."},
58     {static_cast<int32_t>(HttpErrorCode::HTTP_REMOTE_DISK_FULL), "Disk full or allocation exceeded."},
59     {static_cast<int32_t>(HttpErrorCode::HTTP_REMOTE_FILE_EXISTS), "Remote file already exists."},
60     {static_cast<int32_t>(HttpErrorCode::HTTP_SSL_CACERT_BADFILE),
61         "Problem with the SSL CA cert (path? access rights?)."},
62     {static_cast<int32_t>(HttpErrorCode::HTTP_REMOTE_FILE_NOT_FOUND), "Remote file not found."},
63     {static_cast<int32_t>(HttpErrorCode::HTTP_AUTH_ERROR), "An authentication function returned an error."},
64     {static_cast<int32_t>(HttpErrorCode::HTTP_UNKNOWN_OTHER_ERROR), "Unknown Other Error."},
65 };
RequestContext()66 RequestContext::RequestContext()
67 {
68     StartTiming();
69 }
70 
StartTiming()71 void RequestContext::StartTiming()
72 {
73     time_t startTime = TimeUtils::GetNowTimeMicroseconds();
74     timerMap_.RecieveTimer(RESPONSE_HEADER_TIMING).Start(startTime);
75     timerMap_.RecieveTimer(RESPONSE_BODY_TIMING).Start(startTime);
76     timerMap_.RecieveTimer(RESPONSE_TOTAL_TIMING).Start(startTime);
77 }
78 
HandleMethodForGet(CArrUI8 extraData)79 void RequestContext::HandleMethodForGet(CArrUI8 extraData)
80 {
81     if (extraData.head == nullptr) {
82         return;
83     }
84     std::string url = options.GetUrl();
85     std::string param;
86     auto index = url.find(HTTP_URL_PARAM_START);
87     if (index != std::string::npos) {
88         param = url.substr(index + 1);
89         url.resize(index);
90     }
91     std::string extraParam{extraData.head, extraData.head + extraData.size};
92 
93     options.SetUrl(NetHttpClientExec::MakeUrl(url, param, extraParam));
94     return;
95 }
96 
GetRequestBody(CArrUI8 extraData)97 bool RequestContext::GetRequestBody(CArrUI8 extraData)
98 {
99     /* if body is empty, return false, or curl will wait for body */
100 
101     if (extraData.head == nullptr) {
102         return false;
103     }
104     options.SetBody(extraData.head, extraData.size);
105     return true;
106 }
107 
IsUsingCache() const108 bool RequestContext::IsUsingCache() const
109 {
110     return usingCache_;
111 }
112 
SetCurlHeaderList(struct curl_slist * curlHeaderList)113 void RequestContext::SetCurlHeaderList(struct curl_slist *curlHeaderList)
114 {
115     curlHeaderList_ = curlHeaderList;
116 }
117 
GetCurlHeaderList()118 struct curl_slist *RequestContext::GetCurlHeaderList()
119 {
120     return curlHeaderList_;
121 }
~RequestContext()122 RequestContext::~RequestContext()
123 {
124     if (curlHeaderList_ != nullptr) {
125         curl_slist_free_all(curlHeaderList_);
126     }
127     if (multipart_ != nullptr) {
128         curl_mime_free(multipart_);
129         multipart_ = nullptr;
130     }
131     NETSTACK_LOGI("RequestContext is destructed by the destructor");
132 }
133 
SetCacheResponse(const HttpResponse & cacheResponse)134 void RequestContext::SetCacheResponse(const HttpResponse &cacheResponse)
135 {
136     cacheResponse_ = cacheResponse;
137 }
SetResponseByCache()138 void RequestContext::SetResponseByCache()
139 {
140     response = cacheResponse_;
141 }
142 
GetErrorCode() const143 int32_t RequestContext::GetErrorCode() const
144 {
145     if (IsPermissionDenied()) {
146         return PERMISSION_DENIED_CODE;
147     }
148 
149     if (HTTP_ERR_MAP.find(errCode_ + static_cast<int32_t>(HttpErrorCode::HTTP_ERROR_CODE_BASE))
150             != HTTP_ERR_MAP.end()) {
151         return errCode_ + static_cast<int32_t>(HttpErrorCode::HTTP_ERROR_CODE_BASE);
152     }
153     return static_cast<int32_t>(HttpErrorCode::HTTP_UNKNOWN_OTHER_ERROR);
154 }
155 
GetErrorMessage() const156 std::string RequestContext::GetErrorMessage() const
157 {
158     if (IsPermissionDenied()) {
159         return PERMISSION_DENIED_MSG;
160     }
161 
162     auto pos = HTTP_ERR_MAP.find(errCode_ + static_cast<int32_t>(HttpErrorCode::HTTP_ERROR_CODE_BASE));
163     if (pos != HTTP_ERR_MAP.end()) {
164         return pos->second;
165     }
166     return HTTP_ERR_MAP.at(static_cast<int32_t>(HttpErrorCode::HTTP_UNKNOWN_OTHER_ERROR));
167 }
168 
SetErrorCode(int32_t code)169 void RequestContext::SetErrorCode(int32_t code)
170 {
171     errCode_ = code;
172 }
173 
EnableRequestInStream()174 void RequestContext::EnableRequestInStream()
175 {
176     requestInStream_ = true;
177 }
178 
IsRequestInStream() const179 bool RequestContext::IsRequestInStream() const
180 {
181     return requestInStream_;
182 }
183 
SetDlLen(curl_off_t nowLen,curl_off_t totalLen)184 void RequestContext::SetDlLen(curl_off_t nowLen, curl_off_t totalLen)
185 {
186     std::lock_guard<std::mutex> lock(dlLenLock_);
187     LoadBytes dlBytes{nowLen, totalLen};
188     dlBytes_.push(dlBytes);
189 }
190 
SetUlLen(curl_off_t nowLen,curl_off_t totalLen)191 void RequestContext::SetUlLen(curl_off_t nowLen, curl_off_t totalLen)
192 {
193     std::lock_guard<std::mutex> lock(ulLenLock_);
194     if (!ulBytes_.empty()) {
195         ulBytes_.pop();
196     }
197     LoadBytes ulBytes{nowLen, totalLen};
198     ulBytes_.push(ulBytes);
199 }
200 
GetDlLen()201 LoadBytes RequestContext::GetDlLen()
202 {
203     std::lock_guard<std::mutex> lock(dlLenLock_);
204     LoadBytes dlBytes;
205     if (!dlBytes_.empty()) {
206         dlBytes.nLen = dlBytes_.front().nLen;
207         dlBytes.tLen = dlBytes_.front().tLen;
208         dlBytes_.pop();
209     }
210     return dlBytes;
211 }
212 
GetUlLen()213 LoadBytes RequestContext::GetUlLen()
214 {
215     std::lock_guard<std::mutex> lock(ulLenLock_);
216     LoadBytes ulBytes;
217     if (!ulBytes_.empty()) {
218         ulBytes.nLen = ulBytes_.back().nLen;
219         ulBytes.tLen = ulBytes_.back().tLen;
220     }
221     return ulBytes;
222 }
223 
CompareWithLastElement(curl_off_t nowLen,curl_off_t totalLen)224 bool RequestContext::CompareWithLastElement(curl_off_t nowLen, curl_off_t totalLen)
225 {
226     std::lock_guard<std::mutex> lock(ulLenLock_);
227     if (ulBytes_.empty()) {
228         return false;
229     }
230     const LoadBytes &lastElement = ulBytes_.back();
231     return nowLen == lastElement.nLen && totalLen == lastElement.tLen;
232 }
233 
SetTempData(const void * data,size_t size)234 void RequestContext::SetTempData(const void *data, size_t size)
235 {
236     std::lock_guard<std::mutex> lock(tempDataLock_);
237     std::string tempString;
238     tempString.append(reinterpret_cast<const char *>(data), size);
239     tempData_.push(tempString);
240 }
241 
GetTempData()242 std::string RequestContext::GetTempData()
243 {
244     std::lock_guard<std::mutex> lock(tempDataLock_);
245     if (!tempData_.empty()) {
246         return tempData_.front();
247     }
248     return {};
249 }
250 
PopTempData()251 void RequestContext::PopTempData()
252 {
253     std::lock_guard<std::mutex> lock(tempDataLock_);
254     if (!tempData_.empty()) {
255         tempData_.pop();
256     }
257 }
258 
CachePerformanceTimingItem(const std::string & key,double value)259 void RequestContext::CachePerformanceTimingItem(const std::string &key, double value)
260 {
261     performanceTimingMap_[key] = value;
262 }
263 
StopAndCachePerformanceTiming(const char * key)264 void RequestContext::StopAndCachePerformanceTiming(const char *key)
265 {
266     Timer &timer = timerMap_.RecieveTimer(key);
267     timer.Stop();
268     CachePerformanceTimingItem(key, timer.Elapsed());
269 }
270 
SetPerformanceTimingToResult(CHttpResponse & resp)271 void RequestContext::SetPerformanceTimingToResult(CHttpResponse &resp)
272 {
273     if (performanceTimingMap_.empty()) {
274         NETSTACK_LOGI("Get performanceTiming data is empty.");
275         return;
276     }
277 
278     CPerformanceTiming timing{
279         .dnsTiming = performanceTimingMap_[RESPONSE_DNS_TIMING],
280         .tcpTiming = performanceTimingMap_[RESPONSE_TCP_TIMING],
281         .tlsTiming = performanceTimingMap_[RESPONSE_TLS_TIMING],
282         .firstSendTiming = performanceTimingMap_[RESPONSE_FIRST_SEND_TIMING],
283         .firstReceiveTiming = performanceTimingMap_[RESPONSE_FIRST_RECEIVE_TIMING],
284         .totalFinishTiming = performanceTimingMap_[RESPONSE_TOTAL_FINISH_TIMING],
285         .redirectTiming = performanceTimingMap_[RESPONSE_REDIRECT_TIMING],
286         .responseHeaderTiming = performanceTimingMap_[RESPONSE_HEADER_TIMING],
287         .responseBodyTiming = performanceTimingMap_[RESPONSE_BODY_TIMING],
288         .totalTiming = performanceTimingMap_[RESPONSE_TOTAL_TIMING]
289     };
290     resp.performanceTiming = timing;
291 }
292 
SetMultipart(curl_mime * multipart)293 void RequestContext::SetMultipart(curl_mime *multipart)
294 {
295     multipart_ = multipart;
296 }
297 
SetParseOK()298 void RequestContext::SetParseOK()
299 {
300     parseok_ = true;
301 }
302 
IsParseOK() const303 bool RequestContext::IsParseOK() const
304 {
305     return parseok_;
306 }
307 
SetExecOK(bool ok)308 void RequestContext::SetExecOK(bool ok)
309 {
310     requestOK_ = ok;
311 }
312 
IsExecOK() const313 bool RequestContext::IsExecOK() const
314 {
315     return requestOK_;
316 }
317 
SetPermissionDenied(bool deny)318 void RequestContext::SetPermissionDenied(bool deny)
319 {
320     permissionDenied_ = deny;
321 }
322 
IsPermissionDenied() const323 bool RequestContext::IsPermissionDenied() const
324 {
325     return permissionDenied_;
326 }
327 
Destroy()328 void RequestContext::Destroy()
329 {
330     isDestroyed_ = true;
331 }
332 
IsDestroyed() const333 bool RequestContext::IsDestroyed() const
334 {
335     return isDestroyed_;
336 }
337 
SetCertsPath(std::vector<std::string> && certPathList,const std::string & certFile)338 void RequestContext::SetCertsPath(std::vector<std::string> &&certPathList, const std::string &certFile)
339 {
340     certsPath_.certPathList = std::move(certPathList);
341     certsPath_.certFile = certFile;
342 }
343 
GetCertsPath()344 const CertsPath &RequestContext::GetCertsPath()
345 {
346     return certsPath_;
347 }
348 
ParseParams(std::string url,CHttpRequestOptions * ops)349 void RequestContext::ParseParams(std::string url, CHttpRequestOptions *ops)
350 {
351     options.SetUrl(url);
352     if (ops != nullptr) {
353         options.SetMethod(std::string(ops->method));
354         options.SetReadTimeout(ops->readTimeout);
355         options.SetMaxLimit(ops->maxLimit);
356         options.SetConnectTimeout(ops->connectTimeout);
357         usingCache_ = ops->usingCache;
358         if (ops->usingProtocol == static_cast<int32_t>(HttpProtocol::HTTP1_1) ||
359             ops->usingProtocol == static_cast<int32_t>(HttpProtocol::HTTP2)) {
360                 options.SetUsingProtocol(static_cast<HttpProtocol>(ops->usingProtocol));
361             }
362         if (ops->expectDataType != PROP_UNSET) {
363             options.SetHttpDataType(static_cast<HttpDataType>(ops->expectDataType));
364         }
365         options.SetPriority(ops->priority);
366         ParseUsingHttpProxy(ops->usingProxy, ops->usingDefaultProxy);
367         if (ops->clientCert != nullptr) {
368             std::string certPath{ops->clientCert->certPath};
369             std::string certType{ops->clientCert->certType};
370             std::string keyPath{ops->clientCert->keyPath};
371             SecureChar keyPasswd;
372             if (ops->clientCert->keyPassword != nullptr) {
373                 keyPasswd = SecureChar(ops->clientCert->keyPassword);
374             } else {
375                 keyPasswd = SecureChar("");
376             }
377             options.SetClientCert(certPath, certType, keyPath, keyPasswd);
378         }
379         if (!ParseExtraData(ops->extraData)) {
380             return;
381         }
382         ParseHeader(ops->header);
383         if (ops->caPath != nullptr) {
384             options.SetCaPath(std::string{ops->caPath});
385         }
386         if (ops->dnsOverHttps != nullptr) {
387             options.SetDohUrl(std::string{ops->dnsOverHttps});
388         }
389         options.SetRangeNumber(ops->resumeFrom, ops->resumeTo);
390         ParseDnsServers(ops->dnsServer);
391         ParseMultiFormData(ops->multiFormDataList);
392     }
393     SetParseOK();
394 }
395 
ParseUsingHttpProxy(CHttpProxy * proxy,bool useDefault)396 void RequestContext::ParseUsingHttpProxy(CHttpProxy* proxy, bool useDefault)
397 {
398     if (proxy != nullptr) {
399         options.SetUsingHttpProxyType(UsingHttpProxyType::USE_SPECIFIED);
400         std::string host{proxy->host};
401         std::string exclusionList;
402         for (int i = 0; i < proxy->exclusionListSize; i++) {
403             if (i != 0) {
404                 exclusionList = exclusionList + HTTP_PROXY_EXCLUSIONS_SEPARATOR;
405             }
406             exclusionList += std::string{proxy->exclusionList[i]};
407         }
408         options.SetSpecifiedHttpProxy(host, proxy->port, exclusionList);
409     } else {
410         UsingHttpProxyType usingType = useDefault ? UsingHttpProxyType::USE_DEFAULT : UsingHttpProxyType::NOT_USE;
411         options.SetUsingHttpProxyType(usingType);
412     }
413 }
414 
ParseHeader(CArrString header)415 void RequestContext::ParseHeader(CArrString header)
416 {
417     if (header.head == nullptr || header.size == 0) {
418         return;
419     }
420     if (NetHttpClientExec::MethodForPost(options.GetMethod())) {
421         options.SetHeader(CommonUtils::ToLower(HTTP_CONTENT_TYPE), HTTP_CONTENT_TYPE_JSON); // default
422     }
423     for (int i = 0; i < header.size; i += MAP_TUPLE_SIZE) {
424         std::string key{header.head[i]};
425         std::string value{header.head[i + 1]};
426         options.SetHeader(CommonUtils::ToLower(key), value);
427     }
428 }
429 
ParseDnsServers(CArrString dns)430 void RequestContext::ParseDnsServers(CArrString dns)
431 {
432     if (dns.size == 0) {
433         return;
434     }
435     std::vector<std::string> dnsServers;
436     uint32_t dnsSize = 0;
437     for (uint32_t i = 0; i < dns.size && dnsSize < DNS_SERVER_SIZE; i++) {
438         std::string dnsServer{dns.head[i]};
439         if (dnsServer.empty()) {
440             continue;
441         }
442         if (!CommonUtils::IsValidIPV4(dnsServer) && !CommonUtils::IsValidIPV6(dnsServer)) {
443             continue;
444         }
445         dnsServers.push_back(dnsServer);
446         dnsSize++;
447     }
448     options.SetDnsServers(dnsServers);
449 }
450 
ParseExtraData(CArrUI8 data)451 bool RequestContext::ParseExtraData(CArrUI8 data)
452 {
453     if (data.size == 0) {
454         return true;
455     }
456     if (NetHttpClientExec::MethodForGet(options.GetMethod())) {
457         HandleMethodForGet(data);
458         return true;
459     }
460 
461     if (NetHttpClientExec::MethodForPost(options.GetMethod())) {
462         return GetRequestBody(data);
463     }
464     return false;
465 }
466 
ParseMultiFormData(CArrMultiFormData multi)467 void RequestContext::ParseMultiFormData(CArrMultiFormData multi)
468 {
469     if (multi.size == 0) {
470         return;
471     }
472 
473     for (int i = 0; i < multi.size; i++) {
474         CMultiFormData from = multi.data[i];
475         MultiFormData multiFormData;
476         multiFormData.name = std::string{from.name};
477         multiFormData.contentType = std::string{from.contentType};
478         if (from.remoteFileName != nullptr) {
479             multiFormData.remoteFileName = std::string{from.remoteFileName};
480         }
481         if (from.filePath != nullptr) {
482             multiFormData.filePath = std::string{from.filePath};
483         }
484         if (from.data.size > 0) {
485             std::string data{from.data.head, from.data.head + from.data.size};
486             multiFormData.data = data;
487         }
488         options.AddMultiFormData(multiFormData);
489     }
490 }
491 
ParseSetCookie(CArrString & setCookie,HttpResponse & response)492 void ParseSetCookie(CArrString &setCookie, HttpResponse &response)
493 {
494     auto setCookieSize = response.GetsetCookie().size();
495     if (setCookieSize > 0 && setCookieSize < RESPONSE_MAX_SIZE) {
496         setCookie.head = static_cast<char**>(malloc(sizeof(char*) * setCookieSize));
497         if (setCookie.head == nullptr) {
498             return;
499         }
500         setCookie.size = static_cast<int64_t>(setCookieSize);
501         int i = 0;
502         for (const auto &cookie : response.GetsetCookie()) {
503             setCookie.head[i] = MallocCString(cookie);
504             i++;
505         }
506     }
507 }
508 
SendResponse()509 void RequestContext::SendResponse()
510 {
511     CHttpResponse resp = { .errCode = 0,
512         .errMsg = nullptr,
513         .result = { .head = nullptr, .size = 0},
514         .resultType = 2,
515         .responseCode = 0,
516         .header = CArrString{ .head = nullptr, .size = 0 },
517         .cookies = nullptr,
518         .setCookie = CArrString{ .head = nullptr, .size = 0 },
519         .performanceTiming = CPerformanceTiming{}};
520     if (IsExecOK()) {
521         resp.responseCode = response.GetResponseCode();
522         if (!IsRequestInStream()) {
523             auto headerSize = response.GetHeader().size();
524             resp.cookies = MallocCString(response.GetCookies());
525             if (headerSize > 0) {
526                 resp.header = g_map2CArrString(response.GetHeader());
527             }
528             ParseSetCookie(resp.setCookie, response);
529             StopAndCachePerformanceTiming(RESPONSE_TOTAL_TIMING);
530             SetPerformanceTimingToResult(resp);
531             resp.result.head = reinterpret_cast<uint8_t*>(MallocCString(response.GetResult()));
532             resp.result.size = static_cast<int64_t>(response.GetResult().length());
533             resp.resultType = static_cast<int32_t>(options.GetHttpDataType());
534         }
535     } else {
536         resp.errCode = GetErrorCode();
537         resp.errMsg = MallocCString(GetErrorMessage());
538     }
539     respCallback(resp);
540 }
541 
Request(std::string url,CHttpRequestOptions * ops,bool isInStream)542 RequestContext* HttpRequestProxy::Request(std::string url, CHttpRequestOptions *ops, bool isInStream)
543 {
544     if (!NetHttpClientExec::Initialize()) {
545         return nullptr;
546     }
547 
548     RequestContext* context = new RequestContext();
549     if (context == nullptr) {
550         return nullptr;
551     }
552     if (!CommonUtils::HasInternetPermission()) {
553         context->SetPermissionDenied(true);
554         return context;
555     }
556     context->options.SetRequestTime(GetNowTimeGMT());
557     if (isInStream) {
558         context->EnableRequestInStream();
559     }
560     context->ParseParams(url, ops);
561 
562     if (!context->IsParseOK()) {
563         // context.setxxx
564         return context;
565     }
566     NetHttpClientExec::ExecRequest(context);
567     return context;
568 }
569 
Destroy()570 void HttpRequestProxy::Destroy()
571 {
572     isDestroyed = true;
573 
574     // clear funcs
575     callbacks->headersReceive.clear();
576     callbacks->headersReceiveOnce.clear();
577     callbacks->dataReceive.clear();
578     callbacks->dataEnd.clear();
579     callbacks->dataReceiveProgress.clear();
580     callbacks->dataSendProgress.clear();
581 }
582 
583 } // namespace OHOS::NetStack::Http
584