• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "rawfile_request.h"
17 #include "threads.h"
18 
19 #include "hilog/log.h"
20 #include "rawfile/raw_file.h"
21 #include "rawfile/raw_file_manager.h"
22 
23 #undef LOG_TAG
24 #define LOG_TAG "ss-handler"
25 
26 namespace {
27 
28 uint8_t g_buffer[1024];
29 cnd_t g_httpBodyCnd;
30 mtx_t g_httpBodyMtx;
31 const int HTTP_OK = 200;
32 const int HTTP_NOT_FOUND = 404;
33 const int BUFFER_SIZE = 1000;
34 
35 // HttpBodyStream的读回调。
ReadCallback(const ArkWeb_HttpBodyStream * httpBodyStream,uint8_t * buffer,int bytesRead)36 void ReadCallback(const ArkWeb_HttpBodyStream  *httpBodyStream, uint8_t* buffer, int bytesRead)
37 {
38     OH_LOG_INFO(LOG_APP, "read http body back.");
39     bool isEof = OH_ArkWebHttpBodyStream_IsEof(httpBodyStream);
40     if (!isEof && bytesRead != 0) {
41         memset(buffer, 0, BUFFER_SIZE);
42         OH_ArkWebHttpBodyStream_Read(httpBodyStream, buffer, BUFFER_SIZE);
43     } else {
44         RawfileRequest *rawfileRequest = (RawfileRequest *)OH_ArkWebHttpBodyStream_GetUserData(httpBodyStream);
45         if (rawfileRequest) {
46             rawfileRequest->ReadRawfileDataOnWorkerThread();
47             cnd_signal(&g_httpBodyCnd);
48         }
49     }
50 }
51 
ReadHttpBodyOnWorkerThread(void * userData)52 int ReadHttpBodyOnWorkerThread(void* userData)
53 {
54     memset(g_buffer, 0, BUFFER_SIZE);
55     ArkWeb_HttpBodyStream *httpBodyStream = (ArkWeb_HttpBodyStream *)userData;
56     OH_ArkWebHttpBodyStream_Read(httpBodyStream, g_buffer, BUFFER_SIZE);
57     int initResult = cnd_init(&g_httpBodyCnd);
58     if (initResult == 0) {
59         OH_LOG_INFO(LOG_APP, "cnd_init success.");
60     } else {
61         OH_LOG_INFO(LOG_APP, "cnd_init fail.");
62     }
63     int mtxResult = mtx_init(&g_httpBodyMtx, mtx_plain);
64     if (mtxResult == 0) {
65         OH_LOG_INFO(LOG_APP, "mtx_init success.");
66     } else {
67         OH_LOG_INFO(LOG_APP, "mtx_init fail.");
68     }
69     int waitResult = cnd_wait(&g_httpBodyCnd, &g_httpBodyMtx);
70     if (waitResult == 0) {
71         OH_LOG_INFO(LOG_APP, "cnd_wait success.");
72     } else {
73         OH_LOG_INFO(LOG_APP, "cnd_wait fail.");
74     }
75     return 0;
76 }
77 
ReadRawfileOnWorkerThread(void * userData)78 int ReadRawfileOnWorkerThread(void* userData)
79 {
80     RawfileRequest* rawfileRequest = (RawfileRequest*)userData;
81     if (rawfileRequest) {
82         rawfileRequest->ReadRawfileDataOnWorkerThread();
83     }
84     return 0;
85 }
86 
87 // ArkWeb_HttpBodyStream的初始化回调。
InitCallback(const ArkWeb_HttpBodyStream * httpBodyStream,ArkWeb_NetError result)88 void InitCallback(const ArkWeb_HttpBodyStream *httpBodyStream, ArkWeb_NetError result)
89 {
90     OH_LOG_INFO(LOG_APP, "init http body stream done %{public}d.", result);
91     bool isChunked = OH_ArkWebHttpBodyStream_IsChunked(httpBodyStream);
92     OH_LOG_INFO(LOG_APP, "http body stream is chunked %{public}d.", isChunked);
93     thrd_t th;
94     if (thrd_create(&th, ReadHttpBodyOnWorkerThread, (void *)httpBodyStream) != thrd_success) {
95         OH_LOG_ERROR(LOG_APP, "create thread failed.");
96         return;
97     }
98 
99     if (thrd_detach(th) != thrd_success) {
100         OH_LOG_ERROR(LOG_APP, "detach thread failed.");
101     }
102 }
103 
104 const int BLOCK_SIZE = 1024 * 8;
105 const int MAXWHILE = 100;
106 
107 }  // namespace
108 
RawfileRequest(const ArkWeb_ResourceRequest * resourceRequest,const ArkWeb_ResourceHandler * resourceHandler,const NativeResourceManager * resourceManager)109 RawfileRequest::RawfileRequest(const ArkWeb_ResourceRequest *resourceRequest,
110                                const ArkWeb_ResourceHandler *resourceHandler,
111                                const NativeResourceManager* resourceManager)
112     : resourceRequest_(resourceRequest),
113     resourceHandler_(resourceHandler),
114     resourceManager_(resourceManager) {}
115 
~RawfileRequest()116 RawfileRequest::~RawfileRequest() {}
117 
Start()118 void RawfileRequest::Start()
119 {
120     OH_LOG_INFO(LOG_APP, "start a rawfile request.");
121     char* url;
122     OH_ArkWebResourceRequest_GetUrl(resourceRequest_, &url);
123     std::string urlStr(url);
124     std::size_t position = urlStr.rfind('/');
125     if (position != std::string::npos) {
126         rawfilePath_ = urlStr.substr(position + 1);
127     }
128     OH_ArkWeb_ReleaseString(url);
129 
130     OH_ArkWeb_CreateResponse(&response_);
131     OH_ArkWebResourceRequest_GetHttpBodyStream(resourceRequest(), &stream_);
132     if (stream_) {
133         OH_LOG_ERROR(LOG_APP, "have http body stream");
134         OH_ArkWebHttpBodyStream_SetUserData(stream_, this);
135         OH_ArkWebHttpBodyStream_SetReadCallback(stream_, ReadCallback);
136         OH_ArkWebHttpBodyStream_Init(stream_, InitCallback);
137     } else {
138         thrd_t th;
139         if (thrd_create(&th, ReadRawfileOnWorkerThread, static_cast<void*>(this)) != thrd_success) {
140             OH_LOG_ERROR(LOG_APP, "create thread failed.");
141             return;
142         }
143 
144         if (thrd_detach(th) != thrd_success) {
145             OH_LOG_ERROR(LOG_APP, "detach thread failed.");
146         }
147     }
148 }
149 
150 // 在worker线程中读取rawfile,并通过ResourceHandler返回给Web内核。
ReadRawfileDataOnWorkerThread()151 void RawfileRequest::ReadRawfileDataOnWorkerThread()
152 {
153     OH_LOG_INFO(LOG_APP, "read rawfile in worker thread.");
154     const struct UrlInfo {
155         std::string resource;
156         std::string mimeType;
157     } urlInfos[] = {
158         {"test.html", "text/html"},
159         {"video.html", "text/html"},
160         {"isolated.html", "text/html"},
161         {"csp_bypassing.html", "text/html"},
162         {"post_data.html", "text/html"},
163         {"chunked_post_stream.html", "text/html"},
164         {"local.html", "text/html"},
165         {"service_worker.html", "text/html"},
166         {"csp_script.js", "text/javascript"},
167         {"sw.js", "text/javascript"},
168         {"isolated_script.js", "text/javascript"},
169         {"local_script.js", "text/javascript"},
170         {"test.mp4", "video/mp4"},
171         {"xhr", "application/json"}
172     };
173 
174     if (!resourceManager()) {
175         OH_LOG_ERROR(LOG_APP, "read rawfile error, resource manager is nullptr.");
176         return;
177     }
178 
179     RawFile *rawfile = OH_ResourceManager_OpenRawFile(resourceManager(), RawfilePath().c_str());
180     if (!rawfile) {
181         OH_ArkWebResponse_SetStatus(response(), HTTP_NOT_FOUND);
182     } else {
183         OH_ArkWebResponse_SetStatus(response(), HTTP_OK);
184     }
185 
186     for (auto &urlInfo : urlInfos) {
187         if (urlInfo.resource == RawfilePath()) {
188             OH_ArkWebResponse_SetMimeType(response(), urlInfo.mimeType.c_str());
189             break;
190         }
191     }
192     OH_ArkWebResponse_SetCharset(response(), "UTF-8");
193 
194     long len = OH_ResourceManager_GetRawFileSize(rawfile);
195     OH_ArkWebResponse_SetHeaderByName(response(), "content-length", std::to_string(len).c_str(), false);
196     DidReceiveResponse();
197 
198     long consumed = 0;
199     uint8_t buffer[BLOCK_SIZE];
200     int i = 0;
201     while (++i < MAXWHILE) {
202         int ret = OH_ResourceManager_ReadRawFile(rawfile, buffer, BLOCK_SIZE);
203         if (ret > 0) {
204             OH_LOG_INFO(LOG_APP, "read rawfile %{public}d bytes.", ret);
205         } else if (ret == 0) {
206             OH_LOG_INFO(LOG_APP, "read rawfile Reached end of file, %{public}d bytes read.", ret);
207             break;
208         } else {
209             OH_LOG_ERROR(LOG_APP, "read rawfile Error, %{public}d bytes read.", ret);
210             break;
211         }
212         consumed += ret;
213         OH_ResourceManager_SeekRawFile(rawfile, consumed, 0);
214         DidReceiveData(buffer, ret);
215         memset(buffer, 0, BLOCK_SIZE);
216     }
217 
218     OH_ResourceManager_CloseRawFile(rawfile);
219     DidFinish();
220 }
221 
Stop()222 void RawfileRequest::Stop()
223 {
224     OH_LOG_INFO(LOG_APP, "stop the rawfile request.");
225     std::lock_guard<std::mutex> guard(mutex_);
226     stopped_ = true;
227     if (response_) {
228         OH_ArkWeb_DestroyResponse(response_);
229     }
230     OH_ArkWebResourceRequest_Destroy(resourceRequest_);
231     OH_ArkWebResourceHandler_Destroy(resourceHandler_);
232 }
233 
DidReceiveResponse()234 void RawfileRequest::DidReceiveResponse()
235 {
236     OH_LOG_INFO(LOG_APP, "did receive response.");
237     std::lock_guard<std::mutex> guard(mutex_);
238     if (!stopped_) {
239         OH_ArkWebResourceHandler_DidReceiveResponse(resourceHandler_, response_);
240     }
241 }
242 
DidReceiveData(const uint8_t * buffer,int64_t bufLen)243 void RawfileRequest::DidReceiveData(const uint8_t *buffer, int64_t bufLen)
244 {
245     OH_LOG_INFO(LOG_APP, "did receive data.");
246     std::lock_guard<std::mutex> guard(mutex_);
247     if (!stopped_) {
248         OH_ArkWebResourceHandler_DidReceiveData(resourceHandler_, buffer, bufLen);
249     }
250 }
251 
DidFinish()252 void RawfileRequest::DidFinish()
253 {
254     OH_LOG_INFO(LOG_APP, "did finish.");
255     std::lock_guard<std::mutex> guard(mutex_);
256     if (!stopped_) {
257         OH_ArkWebResourceHandler_DidFinish(resourceHandler_);
258     }
259 }
260 
DidFailWithError(ArkWeb_NetError errorCode)261 void RawfileRequest::DidFailWithError(ArkWeb_NetError errorCode)
262 {
263     OH_LOG_INFO(LOG_APP, "did finish with error %{public}d.", errorCode);
264     if (!stopped_) {
265         OH_ArkWebResourceHandler_DidFailWithError(resourceHandler_, errorCode);
266     }
267 }