1 /*
2  * Copyright (c) 2022 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 "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 
25 namespace OHOS::NetStack::Websocket {
SendContext(napi_env env,EventManager * manager)26 SendContext::SendContext(napi_env env, EventManager *manager)
27     : BaseContext(env, manager), data(nullptr), length(0), protocol(LWS_WRITE_TEXT)
28 {
29 }
30 
SendContext(napi_env env,const std::shared_ptr<EventManager> & sharedManager)31 SendContext::SendContext(napi_env env, const std::shared_ptr<EventManager> &sharedManager)
32     : BaseContext(env, sharedManager), data(nullptr), length(0), protocol(LWS_WRITE_TEXT)
33 {
34 }
35 
HandleParseString(napi_value * params)36 bool SendContext::HandleParseString(napi_value *params)
37 {
38     NETSTACK_LOGI("SendContext data is String");
39     std::string str = NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]);
40     // must have PRE and POST
41     size_t dataLen = LWS_SEND_BUFFER_PRE_PADDING + str.length() + LWS_SEND_BUFFER_POST_PADDING;
42     if (dataLen == 0 || dataLen > MAX_LIMIT) {
43         NETSTACK_LOGE("SendContext data is exceeded the limit");
44         return false;
45     }
46     data = malloc(dataLen);
47     if (data == nullptr) {
48         NETSTACK_LOGE("no memory");
49         return false;
50     }
51     if (memcpy_s(reinterpret_cast<void *>(reinterpret_cast<uint8_t *>(data) + LWS_SEND_BUFFER_PRE_PADDING),
52                  str.length(), str.c_str(), str.length()) < 0) {
53         NETSTACK_LOGE("copy failed");
54         return false;
55     }
56     length = str.length();
57     protocol = LWS_WRITE_TEXT;
58     return true;
59 }
60 
HandleParseArrayBuffer(napi_value * params)61 bool SendContext::HandleParseArrayBuffer(napi_value *params)
62 {
63     NETSTACK_LOGD("SendContext data is ArrayBuffer");
64     size_t len = 0;
65     void *mem = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), params[0], &len);
66     if (mem == nullptr || len == 0) {
67         NETSTACK_LOGE("no memory");
68         return false;
69     }
70     // must have PRE and POST
71     size_t dataLen = LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING;
72     if (dataLen == 0 || dataLen > MAX_LIMIT) {
73         NETSTACK_LOGE("SendContext data is exceeded the limit");
74         return false;
75     }
76     data = malloc(dataLen);
77     if (data == nullptr) {
78         NETSTACK_LOGE("no memory");
79         return false;
80     }
81     if (memcpy_s(reinterpret_cast<void *>(reinterpret_cast<uint8_t *>(data) + LWS_SEND_BUFFER_PRE_PADDING), len, mem,
82                  len) < 0) {
83         NETSTACK_LOGE("copy failed");
84         return false;
85     }
86     length = len;
87     protocol = LWS_WRITE_BINARY;
88     return true;
89 }
90 
ParseParams(napi_value * params,size_t paramsCount)91 void SendContext::ParseParams(napi_value *params, size_t paramsCount)
92 {
93     if (!CheckParamsType(params, paramsCount)) {
94         NETSTACK_LOGE("SendContext Parse Failed");
95         if (paramsCount == FUNCTION_PARAM_ONE) {
96             if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) {
97                 SetCallback(params[0]);
98             }
99             return;
100         }
101 
102         if (paramsCount == FUNCTION_PARAM_TWO) {
103             if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) {
104                 SetCallback(params[1]);
105             }
106             return;
107         }
108         return;
109     }
110 
111     if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string) {
112         if (!HandleParseString(params)) {
113             return;
114         }
115     } else {
116         if (!HandleParseArrayBuffer(params)) {
117             return;
118         }
119     }
120 
121     if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) {
122         return SetParseOK(SetCallback(params[1]) == napi_ok);
123     }
124 
125     NETSTACK_LOGD("SendContext SetParseOK");
126     return SetParseOK(true);
127 }
128 
CheckParamsType(napi_value * params,size_t paramsCount)129 bool SendContext::CheckParamsType(napi_value *params, size_t paramsCount)
130 {
131     if (paramsCount == FUNCTION_PARAM_ONE) {
132         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string ||
133                NapiUtils::ValueIsArrayBuffer(GetEnv(), params[0]);
134     }
135 
136     if (paramsCount == FUNCTION_PARAM_TWO) {
137         return (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string ||
138                 NapiUtils::ValueIsArrayBuffer(GetEnv(), params[0])) &&
139                NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function;
140     }
141 
142     return false;
143 }
144 
GetErrorCode() const145 int32_t SendContext::GetErrorCode() const
146 {
147     if (BaseContext::IsPermissionDenied()) {
148         return PERMISSION_DENIED_CODE;
149     }
150 
151     auto err = BaseContext::GetErrorCode();
152     if (err == PARSE_ERROR_CODE) {
153         return PARSE_ERROR_CODE;
154     }
155     if (WEBSOCKET_ERR_MAP.find(err) != WEBSOCKET_ERR_MAP.end()) {
156         return err;
157     }
158     return WEBSOCKET_CONNECT_FAILED;
159 }
160 
GetErrorMessage() const161 std::string SendContext::GetErrorMessage() const
162 {
163     if (BaseContext::IsPermissionDenied()) {
164         return PERMISSION_DENIED_MSG;
165     }
166 
167     auto err = BaseContext::GetErrorCode();
168     if (err == PARSE_ERROR_CODE) {
169         return PARSE_ERROR_MSG;
170     }
171     auto it = WEBSOCKET_ERR_MAP.find(err);
172     if (it != WEBSOCKET_ERR_MAP.end()) {
173         return it->second;
174     }
175     it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR);
176     if (it != WEBSOCKET_ERR_MAP.end()) {
177         return it->second;
178     }
179     return {};
180 }
181 } // namespace OHOS::NetStack::Websocket
182