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 }