• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "hilog/log.h"
17 #include "napi/native_api.h"
18 #include "web/arkweb_scheme_handler.h"
19 #include <bits/alltypes.h>
20 #include <string>
21 #include <threads.h>
22 
23 #undef LOG_TAG
24 #define LOG_TAG "ss-handler"
25 
26 ArkWeb_SchemeHandler *g_schemeHandler;
27 ArkWeb_SchemeHandler *g_schemeHandlerFowSW;
28 
29 bool g_testWebServiceWorkerSetSchemeHandler = false;
30 int32_t testWebSchemeHandler_SetOnRequestStart = -1;
31 int32_t testWebSchemeHandler_SetOnRequestStop = -1;
32 bool g_testWebResourceRequestGetRequestHeaders = false;
33 const int BUFF_LEN = 5;
34 const int REDIRECT_CODE = 302;
35 const int OK = 200;
36 
37 class URLRequest {
38 public:
39     URLRequest(const ArkWeb_ResourceRequest *resourceRequest, const ArkWeb_ResourceHandler *resourceHandler,
40                std::string url);
41     ~URLRequest();
42     void StartRead();
43     void Start();
44     void Stop();
resourceHandler()45     const ArkWeb_ResourceHandler *resourceHandler() { return resourceHandler_; }
46     std::string url();
response()47     ArkWeb_Response *response() { return response_; }
48 
49 
50 private:
51     const ArkWeb_ResourceRequest *resourceRequest_;
52     const ArkWeb_ResourceHandler *resourceHandler_;
53     ArkWeb_HttpBodyStream *stream_{nullptr};
54     std::string url_;
55     ArkWeb_Response *response_;
56 };
57 
58 namespace {
59     uint8_t buffer[1024];
60 
InitCallback(const ArkWeb_HttpBodyStream * httpBodyStream,ArkWeb_NetError result)61     void InitCallback(const ArkWeb_HttpBodyStream *httpBodyStream, ArkWeb_NetError result)
62     {
63         std::fill(buffer, buffer + BUFF_LEN, 0);
64         OH_ArkWebHttpBodyStream_Read(httpBodyStream, buffer, BUFF_LEN);
65     }
66 
ReadCallback(const ArkWeb_HttpBodyStream * httpBodyStream,uint8_t * buffer,int bytesRead)67     void ReadCallback(const ArkWeb_HttpBodyStream *httpBodyStream, uint8_t *buffer, int bytesRead)
68     {
69         bool isEof = OH_ArkWebHttpBodyStream_IsEof(httpBodyStream);
70         if (!isEof && bytesRead != 0) {
71             std::fill(buffer, buffer + BUFF_LEN, 0);
72             OH_ArkWebHttpBodyStream_Read(httpBodyStream, buffer, BUFF_LEN);
73             OH_LOG_INFO(LOG_APP, "OH_ArkWebHttpBodyStream_Read");
74         } else {
75             OH_LOG_INFO(LOG_APP, "OH_ArkWeb_ReleaseByteArray");
76             URLRequest *urlRequest = (URLRequest *)OH_ArkWebHttpBodyStream_GetUserData(httpBodyStream);
77             if (urlRequest) {
78                 urlRequest->StartRead();
79             }
80         }
81     }
82 
ReadHTTP302PageOnWorkerThread(void * urlRequest)83     int ReadHTTP302PageOnWorkerThread(void *urlRequest)
84     {
85         OH_LOG_INFO(LOG_APP, "ReadHTTP302PageOnWorkerThread");
86 
87         ArkWeb_Response *response;
88         OH_ArkWeb_CreateResponse(&response);
89         OH_ArkWebResponse_SetError(response, ARKWEB_NET_OK);
90         OH_ArkWebResponse_SetStatus(response, REDIRECT_CODE);
91         OH_ArkWebResponse_SetStatusText(response, "page not found");
92         OH_ArkWebResponse_SetMimeType(response, "text/html");
93         OH_ArkWebResponse_SetUrl(response, "https://www.example.com");
94         OH_ArkWebResponse_SetCharset(response, "utf-8");
95 
96         // response
97         OH_ArkWebResourceHandler_DidReceiveResponse(static_cast<URLRequest *>(urlRequest)->resourceHandler(), response);
98         OH_ArkWebResourceHandler_DidFinish(static_cast<URLRequest *>(urlRequest)->resourceHandler());
99 
100         return 0;
101     }
102 
ReadXHRWithStatusNormalOnWorkerThread(void * urlRequest)103     int ReadXHRWithStatusNormalOnWorkerThread(void *urlRequest)
104     {
105         OH_LOG_ERROR(LOG_APP, "scheme_handler readnormalxhr in worker thread.");
106         ArkWeb_Response *response;
107         OH_ArkWeb_CreateResponse(&response);
108         OH_ArkWebResponse_SetError(response, ARKWEB_NET_OK);
109         OH_ArkWebResponse_SetStatus(response, OK);
110         OH_ArkWebResponse_SetMimeType(response, "text/html");
111         OH_ArkWebResponse_SetCharset(response, "utf-8");
112 
113         OH_ArkWebResponse_SetHeaderByName(response, "Access-Control-Allow-Origin", "*", false);
114 
115         // 模拟一个response.
116         OH_ArkWebResourceHandler_DidReceiveResponse(static_cast<URLRequest *>(urlRequest)->resourceHandler(), response);
117         // 模拟第一份数据。
118         std::string html_str = "{\"wanghui-debug\":\"jsontest\"}";
119         OH_ArkWebResourceHandler_DidReceiveData(static_cast<URLRequest *>(urlRequest)->resourceHandler(),
120                                                 (uint8_t *)html_str.c_str(), html_str.length());
121         OH_ArkWebResourceHandler_DidFinish(static_cast<URLRequest *>(urlRequest)->resourceHandler());
122         return 0;
123     }
124 } // namesapce
125 
126 
URLRequest(const ArkWeb_ResourceRequest * resourceRequest,const ArkWeb_ResourceHandler * resourceHandler,std::string url)127 URLRequest::URLRequest(const ArkWeb_ResourceRequest *resourceRequest, const ArkWeb_ResourceHandler *resourceHandler,
128                        std::string url)
129     : resourceRequest_(resourceRequest), resourceHandler_(resourceHandler), url_(url) {}
130 
131 
StartRead()132 void URLRequest::StartRead()
133 {
134     OH_ArkWeb_CreateResponse(&response_);
135     // 开启线程
136     thrd_t th;
137     ArkWeb_RequestHeaderList* headerList;
138 
139     OH_ArkWebResourceRequest_GetRequestHeaders(resourceRequest_, &headerList);
140     int size = OH_ArkWebRequestHeaderList_GetSize(headerList);
141     for (int i = 0; i < size; i++) {
142         char *key;
143         char *value;
144         OH_ArkWebRequestHeaderList_GetHeader(headerList, i, &key, &value);
145         g_testWebResourceRequestGetRequestHeaders = true;
146     }
147 
148     OH_LOG_INFO(LOG_APP, "OH_ArkWebResourceRequest_GetRequestHeaders after %{public}p", headerList);
149 
150     char *method;
151     char *referrer;
152     OH_ArkWebResourceRequest_GetMethod(resourceRequest_, &method);
153     OH_ArkWebResourceRequest_GetReferrer(resourceRequest_, &referrer);
154 
155     if (url_ == "custom://www.example.com/302.html") {
156         if (thrd_create(&th, ReadHTTP302PageOnWorkerThread, (void *)this) != thrd_success) {
157         } else {
158             thrd_detach(th);
159         }
160     };
161     if (url_ == "custom://www.example.com/xhr/normal/") {
162         if (thrd_create(&th, ReadXHRWithStatusNormalOnWorkerThread, (void *)this) != thrd_success) {
163         } else {
164             thrd_detach(th);
165         }
166     };
167 }
168 
Start()169 void URLRequest::Start()
170 {
171     OH_ArkWebResourceRequest_GetHttpBodyStream(resourceRequest_, &stream_);
172 
173     if (stream_) {
174         OH_ArkWebHttpBodyStream_SetUserData(stream_, this);
175         OH_ArkWebHttpBodyStream_SetReadCallback(stream_, ReadCallback);
176         OH_ArkWebHttpBodyStream_Init(stream_, InitCallback);
177     } else {
178         StartRead();
179     }
180 }
181 
Stop()182 void URLRequest::Stop()
183 {
184 }
185 
186 // 注册三方协议的配置,需要在Web内核初始化之前调用,否则会注册失败。
RegisterCustomSchemes(napi_env env,napi_callback_info info)187 static napi_value RegisterCustomSchemes(napi_env env, napi_callback_info info)
188 {
189     OH_LOG_INFO(LOG_APP, "register custom schemes");
190     OH_ArkWeb_RegisterCustomSchemes("custom", ARKWEB_SCHEME_OPTION_DISPLAY_ISOLATED
191     | ARKWEB_SCHEME_OPTION_FETCH_ENABLED | ARKWEB_SCHEME_OPTION_CORS_ENABLED | ARKWEB_SCHEME_OPTION_CSP_BYPASSING);
192 
193     return nullptr;
194 }
195 
196 // 请求开始的回调,在该函数中我们创建一个RawfileRequest来实现对Web内核请求的拦截。
OnURLRequestStart(const ArkWeb_SchemeHandler * schemeHandler,ArkWeb_ResourceRequest * resourceRequest,const ArkWeb_ResourceHandler * resourceHandler,bool * intercept)197 void OnURLRequestStart(const ArkWeb_SchemeHandler *schemeHandler, ArkWeb_ResourceRequest *resourceRequest,
198                        const ArkWeb_ResourceHandler *resourceHandler, bool *intercept)
199 {
200     void* userdata = OH_ArkWebSchemeHandler_GetUserData(schemeHandler);
201 
202     char* url;
203     OH_ArkWebResourceRequest_GetUrl(resourceRequest, &url);
204 
205     *intercept = true;
206     URLRequest* request = new URLRequest(resourceRequest, resourceHandler, std::string(url));
207     request->Start();
208 }
209 
210 // 请求结束的回调,在该函数中我们需要标记RawfileRequest已经结束了,内部不应该再使用ResourceHandler
OnURLRequestStop(const ArkWeb_SchemeHandler * schemeHandler,const ArkWeb_ResourceRequest * request)211 void OnURLRequestStop(const ArkWeb_SchemeHandler *schemeHandler, const ArkWeb_ResourceRequest *request)
212 {
213     if (!request) {
214         return;
215     }
216 
217     URLRequest* urlRequest = (URLRequest*)OH_ArkWebResourceRequest_GetUserData(request);
218     urlRequest->Stop();
219     // 接口覆盖 OH_ArkWebResourceRequest_DestroyHttpBodyStream
220     ArkWeb_HttpBodyStream *httpBodyStreamTest;
221     OH_ArkWebResourceRequest_GetHttpBodyStream(request, &httpBodyStreamTest);
222     OH_ArkWebResourceRequest_DestroyHttpBodyStream(httpBodyStreamTest);
223     OH_LOG_INFO(LOG_APP, "OH_ArkWebResourceRequest_DestroyHttpBodyStream");
224 }
225 
226 
227 // 设置 SchemeHandler
SetSchemeHandler(napi_env env,napi_callback_info info)228 static napi_value SetSchemeHandler(napi_env env, napi_callback_info info)
229 {
230     OH_LOG_INFO(LOG_APP, "set scheme handler");
231 
232     OH_ArkWeb_CreateSchemeHandler(&g_schemeHandler);
233 
234     testWebSchemeHandler_SetOnRequestStart = OH_ArkWebSchemeHandler_SetOnRequestStart(g_schemeHandler,
235                                                                                       OnURLRequestStart);
236     testWebSchemeHandler_SetOnRequestStop =OH_ArkWebSchemeHandler_SetOnRequestStop(g_schemeHandler, OnURLRequestStop);
237 
238     OH_ArkWeb_SetSchemeHandler("custom", "scheme-handler", g_schemeHandler);
239     g_testWebServiceWorkerSetSchemeHandler = OH_ArkWebServiceWorker_SetSchemeHandler("http", g_schemeHandler);
240     OH_LOG_INFO(LOG_APP, "testWebSchemeHandler_SetOnRequestStart %{public}d", testWebSchemeHandler_SetOnRequestStart);
241     OH_LOG_INFO(LOG_APP, "testWebSchemeHandler_SetOnRequestStop %{public}d", testWebSchemeHandler_SetOnRequestStop);
242     OH_LOG_INFO(LOG_APP, "g_testWebServiceWorkerSetSchemeHandler %{public}d", g_testWebServiceWorkerSetSchemeHandler);
243 
244     return nullptr;
245 }
246 
ServiceWorkerSetSchemeHandler(napi_env env,napi_callback_info info)247 static napi_value ServiceWorkerSetSchemeHandler(napi_env env, napi_callback_info info)
248 {
249     napi_value result;
250     if (g_testWebServiceWorkerSetSchemeHandler) {
251         napi_create_int32(env, 0, &result);
252     } else {
253         napi_create_int32(env, -1, &result);
254     }
255     return result;
256 }
257 
SchemeHandlerSetOnRequestStart(napi_env env,napi_callback_info info)258 static napi_value SchemeHandlerSetOnRequestStart(napi_env env, napi_callback_info info)
259 {
260     napi_value result;
261     if (testWebSchemeHandler_SetOnRequestStart == 0) {
262         napi_create_int32(env, 0, &result);
263     } else {
264         napi_create_int32(env, -1, &result);
265     }
266     return result;
267 }
268 
SchemeHandlerSetOnRequestStop(napi_env env,napi_callback_info info)269 static napi_value SchemeHandlerSetOnRequestStop(napi_env env, napi_callback_info info)
270 {
271     napi_value result;
272     if (testWebSchemeHandler_SetOnRequestStop == 0) {
273         napi_create_int32(env, 0, &result);
274     } else {
275         napi_create_int32(env, -1, &result);
276     }
277     return result;
278 }
279 
ReleaseString(napi_env env,napi_callback_info info)280 static napi_value ReleaseString(napi_env env, napi_callback_info info)
281 {
282     napi_value result;
283     OH_LOG_ERROR(LOG_APP, "ReleaseString ");
284     char* url = new char[1024];
285     OH_ArkWeb_ReleaseString(url);
286     napi_create_int32(env, 0, &result);
287 
288     return result;
289 }
290 
ReleaseByteArray(napi_env env,napi_callback_info info)291 static napi_value ReleaseByteArray(napi_env env, napi_callback_info info)
292 {
293     napi_value result;
294     OH_LOG_ERROR(LOG_APP, "ReleaseByteArray ");
295     uint8_t* buffer = new uint8_t[1024];
296     OH_ArkWeb_ReleaseByteArray(buffer);
297     napi_create_int32(env, 0, &result);
298 
299     return result;
300 }
301 
DestroyResponse(napi_env env,napi_callback_info info)302 static napi_value DestroyResponse(napi_env env, napi_callback_info info)
303 {
304     napi_value result;
305     OH_LOG_ERROR(LOG_APP, "DestroyResponse ");
306     ArkWeb_Response *response;
307     OH_ArkWeb_CreateResponse(&response);
308     OH_ArkWeb_DestroyResponse(response);
309 
310     napi_create_int32(env, 0, &result);
311 
312     return result;
313 }
314 
CreateSchemeHandler(napi_env env,napi_callback_info info)315 static napi_value CreateSchemeHandler(napi_env env, napi_callback_info info)
316 {
317     napi_value result;
318     OH_LOG_ERROR(LOG_APP, "CreateSchemeHandler ");
319     ArkWeb_SchemeHandler* test_schemeHandler;
320     OH_ArkWeb_CreateSchemeHandler(&test_schemeHandler);
321 
322     napi_create_int32(env, 0, &result);
323 
324     return result;
325 }
326 
ResourceRequestGetRequestHeader(napi_env env,napi_callback_info info)327 static napi_value ResourceRequestGetRequestHeader(napi_env env, napi_callback_info info)
328 {
329     napi_value result;
330     OH_LOG_ERROR(LOG_APP, "ResourceRequestGetRequestHeader ");
331     if (g_testWebResourceRequestGetRequestHeaders) {
332         napi_create_int32(env, 0, &result);
333     } else {
334         napi_create_int32(env, -1, &result);
335     }
336     return result;
337 }
338 
HttpBodyStreamGetUserData(napi_env env,napi_callback_info info)339 static napi_value HttpBodyStreamGetUserData(napi_env env, napi_callback_info info)
340 {
341     napi_value result;
342     OH_LOG_ERROR(LOG_APP, "HttpBodyStreamGetUserData ");
343 
344     ArkWeb_HttpBodyStream* httpBodyStream;
345 
346     int data = 100;
347 
348     OH_ArkWebHttpBodyStream_SetUserData(httpBodyStream, (void*)&data);
349     int getData = *(int*)OH_ArkWebHttpBodyStream_GetUserData(httpBodyStream);
350 
351     OH_LOG_ERROR(LOG_APP, "OH_ArkWebHttpBodyStream_GetUserData %{public}d", getData);
352 
353     if (data == getData) {
354         napi_create_int32(env, 0, &result);
355     } else {
356         napi_create_int32(env, -1, &result);
357     }
358 
359     return result;
360 }
361 
362 EXTERN_C_START
Init(napi_env env,napi_value exports)363 static napi_value Init(napi_env env, napi_value exports) {
364     napi_property_descriptor desc[] = {
365         {"setSchemeHandler", nullptr, SetSchemeHandler, nullptr, nullptr, nullptr, napi_default, nullptr},
366         {"registerCustomSchemes", nullptr, RegisterCustomSchemes, nullptr, nullptr, nullptr, napi_default, nullptr},
367         {"serviceWorkerSetSchemeHandler", nullptr, ServiceWorkerSetSchemeHandler, nullptr, nullptr, nullptr,
368          napi_default, nullptr},
369         {"schemeHandlerSetOnRequestStart", nullptr, SchemeHandlerSetOnRequestStart, nullptr, nullptr, nullptr,
370          napi_default, nullptr},
371         {"schemeHandlerSetOnRequestStop", nullptr, SchemeHandlerSetOnRequestStop, nullptr, nullptr, nullptr,
372          napi_default, nullptr},
373         {"releaseString", nullptr, ReleaseString, nullptr, nullptr, nullptr, napi_default, nullptr},
374         {"releaseByteArray", nullptr, ReleaseByteArray, nullptr, nullptr, nullptr, napi_default, nullptr},
375         {"destroyResponse", nullptr, DestroyResponse, nullptr, nullptr, nullptr, napi_default, nullptr},
376         {"createSchemeHandler", nullptr, CreateSchemeHandler, nullptr, nullptr, nullptr, napi_default, nullptr},
377         {"resourceRequestGetRequestHeaders", nullptr, ResourceRequestGetRequestHeader, nullptr, nullptr, nullptr,
378          napi_default, nullptr},
379         {"httpBodyStreamGetUserData", nullptr, HttpBodyStreamGetUserData, nullptr, nullptr, nullptr, napi_default,
380          nullptr}
381 
382     };
383 
384     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
385     return exports;
386 }
387 EXTERN_C_END
388 
389 static napi_module demoModule = {
390     .nm_version = 1,
391     .nm_flags = 0,
392     .nm_filename = nullptr,
393     .nm_register_func = Init,
394     .nm_modname = "entry",
395     .nm_priv = ((void *)0),
396     .reserved = {0},
397     };
398 
RegisterEntryModule(void)399 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
400 
401