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 "server_send_context.h"
17
18 #include "constant.h"
19 #include "netstack_log.h"
20 #include "napi_utils.h"
21 #include "securec.h"
22
23 static constexpr size_t MAX_LIMIT = 5 * 1024 * 1024;
24 namespace OHOS::NetStack::Websocket {
ServerSendContext(napi_env env,const std::shared_ptr<EventManager> & manager)25 ServerSendContext::ServerSendContext(napi_env env, const std::shared_ptr<EventManager> &manager)
26 : BaseContext(env, manager), data(nullptr), length(0), protocol(LWS_WRITE_TEXT), connection() {}
27
28 ServerSendContext::~ServerSendContext() = default;
29
ParseParams(napi_value * params,size_t paramsCount)30 void ServerSendContext::ParseParams(napi_value *params, size_t paramsCount)
31 {
32 if (!CheckParamsType(params, paramsCount)) {
33 NETSTACK_LOGE("SendContext Parse Failed");
34 if (paramsCount == FUNCTION_PARAM_ONE) {
35 if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object) {
36 SetCallback(params[0]);
37 }
38 return;
39 }
40
41 if (paramsCount == FUNCTION_PARAM_TWO) {
42 if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object) {
43 SetCallback(params[1]);
44 }
45 return;
46 }
47 return;
48 }
49
50 if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string) {
51 if (!HandleParseString(params)) {
52 NETSTACK_LOGI("HandleParseString fail");
53 return;
54 }
55 } else {
56 if (!HandleParseArrayBuffer(params)) {
57 NETSTACK_LOGI("HandleParseArrayBuffer fail");
58 return;
59 }
60 }
61
62 if (!HandleParseConnection(GetEnv(), params[1])) {
63 return;
64 }
65 NETSTACK_LOGD("SendContext SetParseOK");
66 return SetParseOK(true);
67 }
68
CheckParamsType(napi_value * params,size_t paramsCount)69 bool ServerSendContext::CheckParamsType(napi_value *params, size_t paramsCount)
70 {
71 if (paramsCount == FUNCTION_PARAM_TWO) {
72 return (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string ||
73 NapiUtils::ValueIsArrayBuffer(GetEnv(), params[0])) &&
74 IsValidWebsocketConnection(GetEnv(), params[1]);
75 }
76 return false;
77 }
78
IsValidWebsocketConnection(napi_env env,napi_value params)79 bool ServerSendContext::IsValidWebsocketConnection(napi_env env, napi_value params)
80 {
81 NETSTACK_LOGI("IsValidWebsocketConnection enter");
82 if (NapiUtils::GetValueType(env, params) != napi_object) {
83 return false;
84 }
85 return (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, params,
86 ContextKey::CLIENT_PORT)) == napi_number) && (NapiUtils::GetValueType(env,
87 NapiUtils::GetNamedProperty(env, params, ContextKey::CLIENT_IP)) == napi_string);
88 }
89
HandleParseString(napi_value * params)90 bool ServerSendContext::HandleParseString(napi_value *params)
91 {
92 NETSTACK_LOGI("Server SendContext data is String");
93 std::string str = NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]);
94 // must have PRE and POST
95 size_t dataLen = LWS_SEND_BUFFER_PRE_PADDING + str.length() + LWS_SEND_BUFFER_POST_PADDING;
96 if (dataLen == 0 || dataLen > MAX_LIMIT) {
97 NETSTACK_LOGE("ServerSendContext data is exceeded the limit");
98 return false;
99 }
100 data = malloc(dataLen);
101 if (data == nullptr) {
102 NETSTACK_LOGE("no memory");
103 return false;
104 }
105 if (memcpy_s(reinterpret_cast<void *>(reinterpret_cast<uint8_t *>(data) + LWS_SEND_BUFFER_PRE_PADDING),
106 str.length(), str.c_str(), str.length()) < 0) {
107 NETSTACK_LOGE("copy failed");
108 free(data);
109 return false;
110 }
111 length = str.length();
112 protocol = LWS_WRITE_TEXT;
113 return true;
114 }
115
HandleParseArrayBuffer(napi_value * params)116 bool ServerSendContext::HandleParseArrayBuffer(napi_value *params)
117 {
118 NETSTACK_LOGI("ServerSendContext data is ArrayBuffer");
119 size_t len = 0;
120 void *mem = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), params[0], &len);
121 if (mem == nullptr || len == 0) {
122 NETSTACK_LOGE("no memory");
123 return false;
124 }
125 // must have PRE and POST
126 size_t dataLen = LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING;
127 if (dataLen == 0 || dataLen > MAX_LIMIT) {
128 NETSTACK_LOGE("ServerSendContext data is exceeded the limit");
129 return false;
130 }
131 data = malloc(dataLen);
132 if (data == nullptr) {
133 NETSTACK_LOGE("no memory");
134 return false;
135 }
136 if (memcpy_s(reinterpret_cast<void *>(reinterpret_cast<uint8_t *>(data) + LWS_SEND_BUFFER_PRE_PADDING), len, mem,
137 len) < 0) {
138 NETSTACK_LOGE("copy failed");
139 free(data);
140 return false;
141 }
142 length = len;
143 protocol = LWS_WRITE_BINARY;
144 return true;
145 }
146
HandleParseConnection(napi_env env,napi_value params)147 bool ServerSendContext::HandleParseConnection(napi_env env, napi_value params)
148 {
149 NETSTACK_LOGI("parse websocketconnection enter");
150 if (NapiUtils::GetValueType(env, params) == napi_object) {
151 uint32_t port = NapiUtils::GetUint32Property(env, params, ContextKey::CLIENT_PORT);
152 if (port == 0) {
153 NETSTACK_LOGE("parse clientPort error");
154 }
155 std::string ip = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::CLIENT_IP);
156 if (ip == "") {
157 NETSTACK_LOGE("parse clientIP error");
158 }
159 SetClientWebSocketConn(port, ip);
160 return true;
161 }
162 return false;
163 }
164
SetClientWebSocketConn(uint32_t & port,std::string & ip)165 void ServerSendContext::SetClientWebSocketConn(uint32_t &port, std::string &ip)
166 {
167 connection.clientPort = port;
168 connection.clientIP = ip;
169 }
170
GetConnection() const171 WebSocketConnection ServerSendContext::GetConnection() const
172 {
173 return connection;
174 }
175
GetErrorCode() const176 int32_t ServerSendContext::GetErrorCode() const
177 {
178 if (BaseContext::IsPermissionDenied()) {
179 return PERMISSION_DENIED_CODE;
180 }
181
182 auto err = BaseContext::GetErrorCode();
183 if (err == PARSE_ERROR_CODE) {
184 return PARSE_ERROR_CODE;
185 }
186 if (WEBSOCKET_ERR_MAP.find(err) != WEBSOCKET_ERR_MAP.end()) {
187 return err;
188 }
189 return WEBSOCKET_CONNECT_FAILED;
190 }
191
GetErrorMessage() const192 std::string ServerSendContext::GetErrorMessage() const
193 {
194 if (BaseContext::IsPermissionDenied()) {
195 return PERMISSION_DENIED_MSG;
196 }
197
198 auto err = BaseContext::GetErrorCode();
199 if (err == PARSE_ERROR_CODE) {
200 return PARSE_ERROR_MSG;
201 }
202 auto it = WEBSOCKET_ERR_MAP.find(err);
203 if (it != WEBSOCKET_ERR_MAP.end()) {
204 return it->second;
205 }
206 it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR);
207 if (it != WEBSOCKET_ERR_MAP.end()) {
208 return it->second;
209 }
210 return {};
211 }
212 } // namespace OHOS::NetStack::Websocket