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