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 "web_scheme_handler_request.h"
17 
18 #include <securec.h>
19 
20 #include "napi_web_scheme_handler_request.h"
21 #include "napi_parse_utils.h"
22 #include "nweb_log.h"
23 #include "business_error.h"
24 #include "web_errors.h"
25 
26 namespace OHOS::NWeb {
27 namespace {
OnRequestStart(const ArkWeb_SchemeHandler * schemeHandler,ArkWeb_ResourceRequest * resourceRequest,const ArkWeb_ResourceHandler * resourceHandler,bool * intercept)28 void OnRequestStart(const ArkWeb_SchemeHandler* schemeHandler,
29                     ArkWeb_ResourceRequest* resourceRequest,
30                     const ArkWeb_ResourceHandler* resourceHandler,
31                     bool* intercept)
32 {
33     WVLOG_D("SchemeHandler OnRequestStart");
34     if (!schemeHandler) {
35         WVLOG_E("OnRequestStart schemeHandler is nullptr");
36         return;
37     }
38     WebSchemeHandler* handler =
39         WebSchemeHandler::GetWebSchemeHandler(schemeHandler);
40     if (!handler) {
41         WVLOG_E("GetWebSchemeHandler failed");
42         return;
43     }
44     handler->RequestStart(resourceRequest, resourceHandler,
45         intercept);
46 }
47 
OnRequestStop(const ArkWeb_SchemeHandler * schemeHandler,const ArkWeb_ResourceRequest * resourceRequest)48 void OnRequestStop(const ArkWeb_SchemeHandler* schemeHandler,
49                    const ArkWeb_ResourceRequest* resourceRequest)
50 {
51     WVLOG_D("SchemeHandler OnRequestStop");
52     if (!schemeHandler) {
53         WVLOG_E("OnRequestStop schemeHandler is nullptr");
54         return;
55     }
56     WebSchemeHandler* handler =
57         WebSchemeHandler::GetWebSchemeHandler(schemeHandler);
58     if (!handler) {
59         WVLOG_E("GetWebSchemeHandler failed");
60         return;
61     }
62     handler->RequestStop(resourceRequest);
63 }
64 }
65 
WebSchemeHandlerRequest(napi_env env)66 WebSchemeHandlerRequest::WebSchemeHandlerRequest(napi_env env)
67     : env_(env)
68 {
69     WVLOG_D("WebSchemeHandlerRequest::WebSchemeHandlerRequest");
70 }
71 
WebSchemeHandlerRequest(napi_env env,const ArkWeb_ResourceRequest * request)72 WebSchemeHandlerRequest::WebSchemeHandlerRequest(napi_env env,
73     const ArkWeb_ResourceRequest* request)
74 {
75     env_ = env;
76     OH_ArkWebResourceRequest_GetUrl(request, &url_);
77     OH_ArkWebResourceRequest_GetMethod(request, &method_);
78     OH_ArkWebResourceRequest_GetReferrer(request, &referrer_);
79     isRedirect_ = OH_ArkWebResourceRequest_IsRedirect(request);
80     isMainFrame_ = OH_ArkWebResourceRequest_IsMainFrame(request);
81     hasGesture_ = OH_ArkWebResourceRequest_HasGesture(request);
82     OH_ArkWebResourceRequest_GetHttpBodyStream(request, &stream_);
83     requestResourceType_ = OH_ArkWebResourceRequest_GetResourceType(request);
84     OH_ArkWebResourceRequest_GetFrameUrl(request, &frameUrl_);
85 
86     ArkWeb_RequestHeaderList* arkWebHeaderlist = nullptr;
87     OH_ArkWebResourceRequest_GetRequestHeaders(request, &arkWebHeaderlist);
88     if (!arkWebHeaderlist) {
89         WVLOG_E("OH_ArkWebRequestHeaderList_Create failed");
90         return;
91     }
92     int32_t size = OH_ArkWebRequestHeaderList_GetSize(arkWebHeaderlist);
93     if (size <= 0) {
94         WVLOG_E("OH_ArkWebRequestHeaderList_GetSize:%{public}d", size);
95         return;
96     }
97     for (int32_t index = 0; index < size; index++) {
98         char* key;
99         char* value;
100         OH_ArkWebRequestHeaderList_GetHeader(arkWebHeaderlist, index, &key, &value);
101         if (!key || !value) {
102             continue;
103         }
104         std::string strKey(key);
105         std::string strValue(value);
106         headerList_.emplace_back(std::make_pair(strKey, strValue));
107         OH_ArkWeb_ReleaseString(key);
108         OH_ArkWeb_ReleaseString(value);
109     }
110     OH_ArkWebRequestHeaderList_Destroy(arkWebHeaderlist);
111 }
112 
~WebSchemeHandlerRequest()113 WebSchemeHandlerRequest::~WebSchemeHandlerRequest()
114 {
115     WVLOG_D("WebSchemeHandlerRequest::~WebSchemeHandlerRequest");
116     OH_ArkWeb_ReleaseString(url_);
117     OH_ArkWeb_ReleaseString(method_);
118     OH_ArkWeb_ReleaseString(referrer_);
119 }
120 
GetRequestUrl()121 char* WebSchemeHandlerRequest::GetRequestUrl()
122 {
123     return url_;
124 }
125 
GetMethod()126 char* WebSchemeHandlerRequest::GetMethod()
127 {
128     return method_;
129 }
130 
GetReferrer()131 char* WebSchemeHandlerRequest::GetReferrer()
132 {
133     return referrer_;
134 }
135 
IsRedirect()136 bool WebSchemeHandlerRequest::IsRedirect()
137 {
138     return isRedirect_;
139 }
140 
IsMainFrame()141 bool WebSchemeHandlerRequest::IsMainFrame()
142 {
143     return isMainFrame_;
144 }
145 
HasGesture()146 bool WebSchemeHandlerRequest::HasGesture()
147 {
148     return hasGesture_;
149 }
150 
GetHeader()151 const WebHeaderList& WebSchemeHandlerRequest::GetHeader()
152 {
153     return headerList_;
154 }
155 
GetHttpBodyStream()156 ArkWeb_HttpBodyStream* WebSchemeHandlerRequest::GetHttpBodyStream()
157 {
158     return stream_;
159 }
160 
GetRequestResourceType()161 int32_t WebSchemeHandlerRequest::GetRequestResourceType()
162 {
163     return requestResourceType_;
164 }
165 
GetFrameUrl()166 char* WebSchemeHandlerRequest::GetFrameUrl()
167 {
168     return frameUrl_;
169 }
170 
WebSchemeHandlerResponse(napi_env env)171 WebSchemeHandlerResponse::WebSchemeHandlerResponse(napi_env env)
172     : env_(env)
173 {
174     WVLOG_D("WebSchemeHandlerResponse::WebSchemeHandlerResponse");
175     OH_ArkWeb_CreateResponse(&response_);
176 }
177 
WebSchemeHandlerResponse(napi_env env,ArkWeb_Response * response)178 WebSchemeHandlerResponse::WebSchemeHandlerResponse(napi_env env,
179     ArkWeb_Response* response)
180     : env_(env), response_(response)
181 {
182     WVLOG_D("WebSchemeHandlerResponse::WebSchemeHandlerResponse");
183 }
184 
~WebSchemeHandlerResponse()185 WebSchemeHandlerResponse::~WebSchemeHandlerResponse()
186 {
187     WVLOG_I("WebSchemeHandlerResponse::~WebSchemeHandlerResponse");
188     (void)env_;
189     (void)response_;
190     OH_ArkWeb_DestroyResponse(response_);
191 }
192 
GetUrl()193 char* WebSchemeHandlerResponse::GetUrl()
194 {
195     if (!response_) {
196         WVLOG_E("WebSchemeHandlerResponse is nullptr");
197         return nullptr;
198     }
199     char* url;
200     OH_ArkWebResponse_GetUrl(response_, &url);
201     return url;
202 }
203 
SetUrl(const char * url)204 int32_t WebSchemeHandlerResponse::SetUrl(const char* url)
205 {
206     return OH_ArkWebResponse_SetUrl(response_, url);
207 }
208 
GetStatus() const209 int32_t WebSchemeHandlerResponse::GetStatus() const
210 {
211     return OH_ArkWebResponse_GetStatus(response_);
212 }
213 
SetStatus(int32_t status)214 int32_t WebSchemeHandlerResponse::SetStatus(int32_t status)
215 {
216     return OH_ArkWebResponse_SetStatus(response_, status);
217 }
218 
GetStatusText()219 char* WebSchemeHandlerResponse::GetStatusText()
220 {
221     if (!response_) {
222         WVLOG_E("WebSchemeHandlerResponse is nullptr");
223         return nullptr;
224     }
225     char *statusText;
226     OH_ArkWebResponse_GetStatusText(response_, &statusText);
227     return statusText;
228 }
229 
SetStatusText(const char * statusText)230 int32_t WebSchemeHandlerResponse::SetStatusText(const char* statusText)
231 {
232     return OH_ArkWebResponse_SetStatusText(response_, statusText);
233 }
234 
GetMimeType()235 char* WebSchemeHandlerResponse::GetMimeType()
236 {
237     if (!response_) {
238         WVLOG_E("WebSchemeHandlerResponse is nullptr");
239         return nullptr;
240     }
241     char *mimeType;
242     OH_ArkWebResponse_GetMimeType(response_, &mimeType);
243     return mimeType;
244 }
245 
SetMimeType(const char * mimeType)246 int32_t WebSchemeHandlerResponse::SetMimeType(const char* mimeType)
247 {
248     return OH_ArkWebResponse_SetMimeType(response_, mimeType);
249 }
250 
GetEncoding() const251 char* WebSchemeHandlerResponse::GetEncoding() const
252 {
253     if (!response_) {
254         WVLOG_E("WebSchemeHandlerResponse is nullptr");
255         return nullptr;
256     }
257     char *encoding;
258     OH_ArkWebResponse_GetCharset(response_, &encoding);
259     return encoding;
260 }
261 
SetEncoding(const char * encoding)262 int32_t WebSchemeHandlerResponse::SetEncoding(const char* encoding)
263 {
264     return OH_ArkWebResponse_SetCharset(response_, encoding);
265 }
266 
GetHeaderByName(const char * name)267 char* WebSchemeHandlerResponse::GetHeaderByName(const char* name)
268 {
269     if (!response_) {
270         WVLOG_E("WebSchemeHandlerResponse is nullptr");
271         return nullptr;
272     }
273     char *value;
274     OH_ArkWebResponse_GetHeaderByName(response_, name, &value);
275     return value;
276 }
277 
SetHeaderByName(const char * name,const char * value,bool overwrite)278 int32_t WebSchemeHandlerResponse::SetHeaderByName(
279     const char* name, const char* value, bool overwrite)
280 {
281     return OH_ArkWebResponse_SetHeaderByName(response_, name, value, overwrite);
282 }
283 
GetErrorCode()284 int32_t WebSchemeHandlerResponse::GetErrorCode()
285 {
286     return static_cast<int32_t>(OH_ArkWebResponse_GetError(response_));
287 }
288 
SetErrorCode(int32_t code)289 int32_t WebSchemeHandlerResponse::SetErrorCode(int32_t code)
290 {
291     return OH_ArkWebResponse_SetError(response_, static_cast<ArkWeb_NetError>(code));
292 }
293 
294 std::unordered_map<WebSchemeHandler*, const ArkWeb_SchemeHandler*>
295     WebSchemeHandler::webSchemeHandlerMap_;
296 std::unordered_map<const ArkWeb_SchemeHandler*, WebSchemeHandler*>
297     WebSchemeHandler::arkWebSchemeHandlerMap_;
298 
GetArkWebSchemeHandler(WebSchemeHandler * handler)299 const ArkWeb_SchemeHandler* WebSchemeHandler::GetArkWebSchemeHandler(
300     WebSchemeHandler* handler)
301 {
302     return WebSchemeHandler::webSchemeHandlerMap_.find(handler) !=
303         WebSchemeHandler::webSchemeHandlerMap_.end() ?
304         WebSchemeHandler::webSchemeHandlerMap_[handler] : nullptr;
305 }
306 
GetWebSchemeHandler(const ArkWeb_SchemeHandler * handler)307 WebSchemeHandler* WebSchemeHandler::GetWebSchemeHandler(const ArkWeb_SchemeHandler* handler)
308 {
309     return WebSchemeHandler::arkWebSchemeHandlerMap_.find(handler) !=
310         WebSchemeHandler::arkWebSchemeHandlerMap_.end() ?
311         WebSchemeHandler::arkWebSchemeHandlerMap_[handler] : nullptr;
312 }
313 
WebSchemeHandler(napi_env env)314 WebSchemeHandler::WebSchemeHandler(napi_env env)
315     : env_(env)
316 {
317     ArkWeb_SchemeHandler* handler;
318     OH_ArkWeb_CreateSchemeHandler(&handler);
319     if (!handler) {
320         WVLOG_E("create WebSchemeHandler failed");
321         return;
322     }
323     onRequestStart_ = &OnRequestStart;
324     onRequestStop_ = &OnRequestStop;
325     OH_ArkWebSchemeHandler_SetOnRequestStart(handler, onRequestStart_);
326     OH_ArkWebSchemeHandler_SetOnRequestStop(handler, onRequestStop_);
327     OH_ArkWebSchemeHandler_SetFromEts(handler, true);
328     webSchemeHandlerMap_.insert(std::make_pair(this, handler));
329     arkWebSchemeHandlerMap_.insert(std::make_pair(handler, this));
330 }
331 
~WebSchemeHandler()332 WebSchemeHandler::~WebSchemeHandler()
333 {
334     WVLOG_D("WebSchemeHandler::~WebSchemeHandler");
335     napi_delete_reference(env_, request_start_callback_);
336     napi_delete_reference(env_, request_stop_callback_);
337     ArkWeb_SchemeHandler* handler =
338         const_cast<ArkWeb_SchemeHandler*>(GetArkWebSchemeHandler(this));
339     if (!handler) {
340         WVLOG_E("~WebSchemeHandler not found ArkWeb_SchemeHandler");
341         return;
342     }
343     webSchemeHandlerMap_.erase(this);
344     arkWebSchemeHandlerMap_.erase(handler);
345     OH_ArkWeb_DestroySchemeHandler(handler);
346 }
347 
RequestStart(ArkWeb_ResourceRequest * request,const ArkWeb_ResourceHandler * ArkWeb_ResourceHandler,bool * intercept)348 void WebSchemeHandler::RequestStart(ArkWeb_ResourceRequest* request,
349                                     const ArkWeb_ResourceHandler* ArkWeb_ResourceHandler,
350                                     bool* intercept)
351 {
352     napi_handle_scope scope = nullptr;
353     napi_open_handle_scope(env_, &scope);
354     if (!scope) {
355         WVLOG_E("scheme handler RequestStart scope is nullptr");
356         return;
357     }
358 
359     WVLOG_D("WebSchemeHandler::RequestStart");
360     size_t paramCount = 2;
361     napi_value callbackFunc = nullptr;
362     napi_status status;
363     if (!request_start_callback_) {
364         WVLOG_E("scheme handler onRequestStart nil env");
365         return;
366     }
367     status = napi_get_reference_value(env_, request_start_callback_, &callbackFunc);
368     if (status != napi_ok || callbackFunc == nullptr) {
369         WVLOG_E("scheme handler get onRequestStart func failed.");
370         return;
371     }
372 
373     napi_value requestValue[2] = {0};
374     napi_create_object(env_, &requestValue[0]);
375     napi_create_object(env_, &requestValue[1]);
376     WebSchemeHandlerRequest* schemeHandlerRequest = new (std::nothrow) WebSchemeHandlerRequest(env_, request);
377     if (schemeHandlerRequest == nullptr) {
378         WVLOG_E("RequestStart, new schemeHandlerRequest failed");
379         return;
380     }
381     sptr<WebResourceHandler> resourceHandler = new (std::nothrow) WebResourceHandler(env_, ArkWeb_ResourceHandler);
382     if (resourceHandler == nullptr) {
383         WVLOG_E("RequestStart, new resourceHandler failed");
384         delete schemeHandlerRequest;
385         return;
386     }
387     if (OH_ArkWebResourceRequest_SetUserData(request, resourceHandler.GetRefPtr()) != 0) {
388         WVLOG_W("OH_ArkWebResourceRequest_SetUserData failed");
389     } else {
390         resourceHandler->IncStrongRef(nullptr);
391     }
392     napi_wrap(
393         env_, requestValue[0], schemeHandlerRequest,
394         [](napi_env /* env */, void *data, void * /* hint */) {
395             WebSchemeHandlerRequest *request = (WebSchemeHandlerRequest *)data;
396             delete request;
397         }, nullptr, nullptr);
398     NapiWebSchemeHandlerRequest::DefineProperties(env_, &requestValue[0]);
399     napi_wrap(
400         env_, requestValue[1], resourceHandler.GetRefPtr(),
401         [](napi_env /* env */, void *data, void * /* hint */) {
402             static_cast<WebResourceHandler*>(data)->DecStrongRef(data);
403         }, nullptr, nullptr);
404     NapiWebResourceHandler::DefineProperties(env_, &requestValue[1]);
405     resourceHandler->IncStrongRef(nullptr);
406     napi_value result = nullptr;
407     status = napi_call_function(
408         env_, nullptr, callbackFunc, paramCount, requestValue, &result);
409     if (status != napi_status::napi_ok) {
410         WVLOG_W("scheme handler call onRequestStart failed.");
411     }
412     if (!NapiParseUtils::ParseBoolean(env_, result, *intercept)) {
413         WVLOG_E("scheme handler onRequestStart intercept parse failed");
414         *intercept = false;
415     }
416     if (!*intercept) {
417         resourceHandler->SetFinishFlag();
418         resourceHandler->DecStrongRef(resourceHandler);
419     }
420     napi_close_handle_scope(env_, scope);
421 }
422 
RequestStopAfterWorkCb(uv_work_t * work,int status)423 void WebSchemeHandler::RequestStopAfterWorkCb(uv_work_t* work, int status)
424 {
425     WVLOG_D("WebSchemeHandler::RequestStopAfterWorkCb");
426     if (!work) {
427         return;
428     }
429     RequestStopParam *param =
430         reinterpret_cast<struct RequestStopParam*>(work->data);
431     if (!param) {
432         delete work;
433         work = nullptr;
434         return;
435     }
436     napi_handle_scope scope = nullptr;
437     napi_open_handle_scope(param->env_, &scope);
438     if (scope == nullptr) {
439         delete param;
440         delete work;
441         return;
442     }
443     napi_value callbackFunc = nullptr;
444     napi_status napiStatus;
445     if (!param->callbackRef_) {
446         WVLOG_E("scheme handler onRequestStop nil env");
447         napi_close_handle_scope(param->env_, scope);
448         delete param;
449         delete work;
450         return;
451     }
452     napiStatus = napi_get_reference_value(param->env_, param->callbackRef_, &callbackFunc);
453     if (napiStatus != napi_ok || callbackFunc == nullptr) {
454         WVLOG_E("scheme handler get onRequestStop func failed.");
455         napi_close_handle_scope(param->env_, scope);
456         delete param;
457         delete work;
458         return;
459     }
460     napi_value requestValue;
461     napi_create_object(param->env_, &requestValue);
462     napi_wrap(
463         param->env_, requestValue, param->request_,
464         [](napi_env /* env */, void *data, void * /* hint */) {
465             WebSchemeHandlerRequest *request = (WebSchemeHandlerRequest *)data;
466             delete request;
467         },
468         nullptr, nullptr);
469     NapiWebSchemeHandlerRequest::DefineProperties(param->env_, &requestValue);
470     napi_value result = nullptr;
471     napiStatus = napi_call_function(
472         param->env_, nullptr, callbackFunc, 1, &requestValue, &result);
473     if (napiStatus != napi_status::napi_ok) {
474         WVLOG_E("scheme handler call onRequestStop failed.");
475     }
476     WebResourceHandler* resourceHandler =
477         reinterpret_cast<WebResourceHandler*>(
478             OH_ArkWebResourceRequest_GetUserData(param->arkWebRequest_));
479     if (resourceHandler) {
480         resourceHandler->SetFinishFlag();
481         resourceHandler->DecStrongRef(resourceHandler);
482     }
483     napi_close_handle_scope(param->env_, scope);
484     delete param;
485     param = nullptr;
486     delete work;
487     work = nullptr;
488 }
489 
RequestStop(const ArkWeb_ResourceRequest * resourceRequest)490 void WebSchemeHandler::RequestStop(const ArkWeb_ResourceRequest* resourceRequest)
491 {
492     WVLOG_D("WebSchemeHandler::RequestStop");
493     uv_loop_s *loop = nullptr;
494     uv_work_t *work = nullptr;
495     napi_get_uv_event_loop(env_, &loop);
496     if (loop == nullptr) {
497         return;
498     }
499     work = new (std::nothrow) uv_work_t;
500     if (work == nullptr) {
501         return;
502     }
503     RequestStopParam *param = new (std::nothrow) RequestStopParam();
504     if (param == nullptr) {
505         delete work;
506         return;
507     }
508     param->env_ = env_;
509     param->callbackRef_ = request_stop_callback_;
510     param->request_ = new (std::nothrow) WebSchemeHandlerRequest(param->env_, resourceRequest);
511     if (param->request_ == nullptr) {
512         delete work;
513         delete param;
514         return;
515     }
516     param->arkWebRequest_ = resourceRequest;
517     work->data = reinterpret_cast<void*>(param);
518     int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {},
519         RequestStopAfterWorkCb, uv_qos_user_initiated);
520     if (ret != 0) {
521         if (param != nullptr) {
522             delete param;
523             param = nullptr;
524         }
525         if (work != nullptr) {
526             delete work;
527             work = nullptr;
528         }
529     }
530 }
531 
PutRequestStart(napi_env,napi_value callback)532 void WebSchemeHandler::PutRequestStart(napi_env, napi_value callback)
533 {
534     WVLOG_D("WebSchemeHandler::PutRequestStart");
535     napi_status status = napi_create_reference(env_, callback, 1, &request_start_callback_);
536     if (status != napi_status::napi_ok) {
537         WVLOG_E("PutRequestStart create reference failed.");
538     }
539 }
PutRequestStop(napi_env,napi_value callback)540 void WebSchemeHandler::PutRequestStop(napi_env, napi_value callback)
541 {
542     WVLOG_D("WebSchemeHandler::PutRequestStop");
543     napi_status status = napi_create_reference(env_, callback, 1, &request_stop_callback_);
544     if (status != napi_status::napi_ok) {
545         WVLOG_E("PutRequestStop create reference failed.");
546     }
547 }
548 
WebResourceHandler(napi_env env)549 WebResourceHandler::WebResourceHandler(napi_env env)
550     : env_(env)
551 {
552     WVLOG_D("create WebResourceHandler");
553 }
554 
WebResourceHandler(napi_env env,const ArkWeb_ResourceHandler * handler)555 WebResourceHandler::WebResourceHandler(napi_env env, const ArkWeb_ResourceHandler* handler)
556     : handler_(const_cast<ArkWeb_ResourceHandler*>(handler))
557 {
558     WVLOG_D("create WebResourceHandler");
559     env_ = env;
560 }
561 
~WebResourceHandler()562 WebResourceHandler::~WebResourceHandler()
563 {
564     WVLOG_D("~WebResourceHandler");
565 }
566 
DidReceiveResponse(const ArkWeb_Response * response)567 int32_t WebResourceHandler::DidReceiveResponse(const ArkWeb_Response* response)
568 {
569     if (isFinished_) {
570         return ArkWeb_ErrorCode::ARKWEB_ERROR_UNKNOWN;
571     }
572     return OH_ArkWebResourceHandler_DidReceiveResponse(handler_, response);
573 }
574 
DidReceiveResponseBody(const uint8_t * buffer,int64_t buflen)575 int32_t WebResourceHandler::DidReceiveResponseBody(const uint8_t* buffer, int64_t buflen)
576 {
577     if (isFinished_) {
578         return ArkWeb_ErrorCode::ARKWEB_ERROR_UNKNOWN;
579     }
580     return OH_ArkWebResourceHandler_DidReceiveData(handler_, buffer, buflen);
581 }
582 
DidFinish()583 int32_t WebResourceHandler::DidFinish()
584 {
585     if (isFinished_) {
586         return ArkWeb_ErrorCode::ARKWEB_ERROR_UNKNOWN;
587     }
588     int32_t ret = OH_ArkWebResourceHandler_DidFinish(handler_);
589     if (ret == 0) {
590         isFinished_ = true;
591     }
592     return ret;
593 }
594 
DidFailWithError(ArkWeb_NetError errorCode)595 int32_t WebResourceHandler::DidFailWithError(ArkWeb_NetError errorCode)
596 {
597     if (isFinished_) {
598         return ArkWeb_ErrorCode::ARKWEB_ERROR_UNKNOWN;
599     }
600     int32_t ret = OH_ArkWebResourceHandler_DidFailWithError(handler_, errorCode);
601     if (ret == 0) {
602         isFinished_ = true;
603     }
604     return ret;
605 }
606 
DestoryArkWebResourceHandler()607 void WebResourceHandler::DestoryArkWebResourceHandler()
608 {
609     if (handler_) {
610         OH_ArkWebResourceHandler_Destroy(handler_);
611         handler_ = nullptr;
612     }
613 }
614 
WebHttpBodyStream(napi_env env)615 WebHttpBodyStream::WebHttpBodyStream(napi_env env)
616 {
617     WVLOG_D("WebHttpBodyStream::WebHttpBodyStream");
618     env_ = env;
619 }
620 
WebHttpBodyStream(napi_env env,ArkWeb_HttpBodyStream * stream)621 WebHttpBodyStream::WebHttpBodyStream(napi_env env,
622     ArkWeb_HttpBodyStream* stream)
623 {
624     WVLOG_D("WebHttpBodyStream::WebHttpBodyStream");
625     env_ = env;
626     stream_ = stream;
627     if (OH_ArkWebHttpBodyStream_SetUserData(stream_, this) != 0) {
628         WVLOG_E("OH_ArkWebHttpBodyStream_SetUserData failed");
629         return;
630     }
631     if (OH_ArkWebHttpBodyStream_SetReadCallback(stream_,
632         &WebHttpBodyStream::HttpBodyStreamReadCallback) != 0) {
633         WVLOG_E("OH_ArkWebHttpBodyStream_SetReadCallback failed");
634         return;
635     }
636 }
637 
~WebHttpBodyStream()638 WebHttpBodyStream::~WebHttpBodyStream()
639 {
640     WVLOG_D("WebHttpBodyStream::~WebHttpBodyStream");
641     if (!stream_) {
642         OH_ArkWebResourceRequest_DestroyHttpBodyStream(stream_);
643         stream_ = nullptr;
644     }
645 }
646 
HttpBodyStreamReadCallback(const ArkWeb_HttpBodyStream * httpBodyStream,uint8_t * buffer,int bytesRead)647 void WebHttpBodyStream::HttpBodyStreamReadCallback(
648     const ArkWeb_HttpBodyStream* httpBodyStream, uint8_t* buffer, int bytesRead)
649 {
650     WVLOG_D("WebHttpBodyStream::HttpBodyStreamReadCallback");
651     WebHttpBodyStream* stream = reinterpret_cast<WebHttpBodyStream*>(
652         OH_ArkWebHttpBodyStream_GetUserData(httpBodyStream));
653     if (!stream) {
654         WVLOG_E("OH_ArkWebHttpBodyStream_GetUserData is nullptr");
655         return;
656     }
657     stream->ExecuteRead(buffer, bytesRead);
658 }
659 
HttpBodyStreamInitCallback(const ArkWeb_HttpBodyStream * httpBodyStream,ArkWeb_NetError result)660 void WebHttpBodyStream::HttpBodyStreamInitCallback(
661     const ArkWeb_HttpBodyStream* httpBodyStream, ArkWeb_NetError result)
662 {
663     WVLOG_D("WebHttpBodyStream::HttpBodyStreamInitCallback");
664     WebHttpBodyStream* stream = reinterpret_cast<WebHttpBodyStream*>(
665         OH_ArkWebHttpBodyStream_GetUserData(httpBodyStream));
666     if (!stream) {
667         WVLOG_E("OH_ArkWebHttpBodyStream_GetUserData is nullptr");
668         return;
669     }
670     stream->ExecuteInit(result);
671 }
672 
Init(napi_ref jsCallback,napi_deferred deferred)673 void WebHttpBodyStream::Init(napi_ref jsCallback, napi_deferred deferred)
674 {
675     if (!jsCallback && !deferred) {
676         WVLOG_E("WebHttpBodyStream::InitCallback callback is nullptr");
677         return;
678     }
679     if (jsCallback) {
680         initJsCallback_ = std::move(jsCallback);
681     }
682     if (deferred) {
683         initDeferred_ = std::move(deferred);
684     }
685     int ret = OH_ArkWebHttpBodyStream_Init(stream_,
686         &WebHttpBodyStream::HttpBodyStreamInitCallback);
687     if (ret != 0) {
688         WVLOG_E("OH_ArkWebHttpBodyStream_Init failed");
689         return;
690     }
691 }
692 
Read(int bufLen,napi_ref jsCallback,napi_deferred deferred)693 void WebHttpBodyStream::Read(int bufLen, napi_ref jsCallback, napi_deferred deferred)
694 {
695     WVLOG_D("WebHttpBodyStream::Read");
696     if (!jsCallback && !deferred) {
697         WVLOG_E("WebHttpBodyStream::Read callback is nullptr");
698         return;
699     }
700     if (bufLen <= 0) {
701         return;
702     }
703     if (jsCallback) {
704         readJsCallback_ = std::move(jsCallback);
705     }
706     if (deferred) {
707         readDeferred_ = std::move(deferred);
708     }
709     uint8_t* buffer = new (std::nothrow) uint8_t[bufLen];
710     if (buffer == nullptr) {
711         return;
712     }
713     OH_ArkWebHttpBodyStream_Read(stream_, buffer, bufLen);
714 }
715 
ExecuteInit(ArkWeb_NetError result)716 void WebHttpBodyStream::ExecuteInit(ArkWeb_NetError result)
717 {
718     WVLOG_D("WebHttpBodyStream::ExecuteInit");
719     if (!env_) {
720         return ;
721     }
722     InitParam *param = new (std::nothrow) InitParam {
723         .env = env_,
724         .asyncWork = nullptr,
725         .deferred = initDeferred_,
726         .callbackRef = initJsCallback_,
727         .result = result,
728     };
729     if (param == nullptr) {
730         return;
731     }
732     napi_value resourceName = nullptr;
733     NAPI_CALL_RETURN_VOID(env_, napi_create_string_utf8(env_, __func__, NAPI_AUTO_LENGTH, &resourceName));
734     NAPI_CALL_RETURN_VOID(env_, napi_create_async_work(env_, nullptr, resourceName,
735         [](napi_env env, void *data) {},
736         ExecuteInitComplete, static_cast<void *>(param), &param->asyncWork));
737     NAPI_CALL_RETURN_VOID(env_, napi_queue_async_work_with_qos(env_, param->asyncWork, napi_qos_user_initiated));
738 }
739 
ExecuteInitComplete(napi_env env,napi_status status,void * data)740 void WebHttpBodyStream::ExecuteInitComplete(napi_env env, napi_status status, void* data)
741 {
742     WVLOG_D("WebHttpBodyStream::ExecuteInitComplete");
743     InitParam* param = static_cast<InitParam*>(data);
744     if (!param) {
745         return;
746     }
747     napi_handle_scope scope = nullptr;
748     napi_open_handle_scope(env, &scope);
749     if (!scope) {
750         delete param;
751         return;
752     }
753     napi_value result[INTEGER_ONE] = {0};
754     if (param->result != 0) {
755         result[INTEGER_ZERO] = NWebError::BusinessError::CreateError(
756             env, NWebError::HTTP_BODY_STREAN_INIT_FAILED);
757     } else {
758         napi_get_null(env, &result[INTEGER_ZERO]);
759     }
760     if (param->callbackRef) {
761         napi_value callback = nullptr;
762         napi_get_reference_value(env, param->callbackRef, &callback);
763         napi_call_function(env, nullptr, callback, INTEGER_ONE, &result[INTEGER_ZERO], nullptr);
764         napi_delete_reference(env, param->callbackRef);
765     } else if (param->deferred) {
766         if (param->result != 0) {
767             napi_reject_deferred(env, param->deferred, result[INTEGER_ZERO]);
768         } else {
769             napi_resolve_deferred(env, param->deferred, result[INTEGER_ZERO]);
770         }
771     }
772     napi_delete_async_work(env, param->asyncWork);
773     napi_close_handle_scope(env, scope);
774     delete param;
775 }
776 
ExecuteReadComplete(napi_env env,napi_status status,void * data)777 void WebHttpBodyStream::ExecuteReadComplete(napi_env env, napi_status status, void* data)
778 {
779     WVLOG_D("WebHttpBodyStream::ExecuteReadComplete");
780     ReadParam* param = static_cast<ReadParam*>(data);
781     if (!param) {
782         return;
783     }
784     napi_handle_scope scope = nullptr;
785     napi_open_handle_scope(env, &scope);
786     if (!scope) {
787         delete param;
788         return;
789     }
790     napi_value result[INTEGER_ONE] = {0};
791     void *bufferData = nullptr;
792     napi_create_arraybuffer(env, param->bytesRead, &bufferData, &result[INTEGER_ZERO]);
793     if (memcpy_s(bufferData, param->bytesRead, param->buffer, param->bytesRead) != 0 &&
794         param->bytesRead > 0) {
795         WVLOG_W("WebHttpBodyStream::ExecuteRead memcpy failed");
796     }
797     if (param->buffer) {
798         delete param->buffer;
799     }
800     if (param->callbackRef) {
801         napi_value callback = nullptr;
802         napi_get_reference_value(env, param->callbackRef, &callback);
803         napi_call_function(env, nullptr, callback, INTEGER_ONE, &result[INTEGER_ZERO], nullptr);
804         napi_delete_reference(env, param->callbackRef);
805     } else if (param->deferred) {
806         napi_resolve_deferred(env, param->deferred, result[INTEGER_ZERO]);
807     }
808     napi_delete_async_work(env, param->asyncWork);
809     napi_close_handle_scope(env, scope);
810     delete param;
811 }
812 
ExecuteRead(uint8_t * buffer,int bytesRead)813 void WebHttpBodyStream::ExecuteRead(uint8_t* buffer, int bytesRead)
814 {
815     if (!env_) {
816         return;
817     }
818     ReadParam *param = new (std::nothrow) ReadParam {
819         .env = env_,
820         .asyncWork = nullptr,
821         .deferred = readDeferred_,
822         .callbackRef = readJsCallback_,
823         .buffer = buffer,
824         .bytesRead = bytesRead,
825     };
826     if (param == nullptr) {
827         return;
828     }
829     napi_value resourceName = nullptr;
830     NAPI_CALL_RETURN_VOID(env_, napi_create_string_utf8(env_, __func__, NAPI_AUTO_LENGTH, &resourceName));
831     NAPI_CALL_RETURN_VOID(env_, napi_create_async_work(env_, nullptr, resourceName,
832         [](napi_env env, void *data) {},
833         ExecuteReadComplete, static_cast<void *>(param), &param->asyncWork));
834     NAPI_CALL_RETURN_VOID(env_,
835         napi_queue_async_work_with_qos(env_, param->asyncWork, napi_qos_user_initiated));
836 }
837 
GetPostion() const838 uint64_t WebHttpBodyStream::GetPostion() const
839 {
840     return OH_ArkWebHttpBodyStream_GetPosition(stream_);
841 }
842 
GetSize() const843 uint64_t WebHttpBodyStream::GetSize() const
844 {
845     return OH_ArkWebHttpBodyStream_GetSize(stream_);
846 }
847 
IsChunked() const848 bool WebHttpBodyStream::IsChunked() const
849 {
850     return OH_ArkWebHttpBodyStream_IsChunked(stream_);
851 }
852 
IsEof()853 bool WebHttpBodyStream::IsEof()
854 {
855     return OH_ArkWebHttpBodyStream_IsEof(stream_);
856 }
857 
IsInMemory()858 bool WebHttpBodyStream::IsInMemory()
859 {
860     return OH_ArkWebHttpBodyStream_IsInMemory(stream_);
861 }
862 }
863