1 /*
2 * Copyright (C) 2021-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 "request_context.h"
17
18 #include <algorithm>
19
20 #include "constant.h"
21 #include "http_exec.h"
22 #include "netstack_common_utils.h"
23 #include "netstack_log.h"
24 #include "netstack_napi_utils.h"
25
26 static constexpr const int PARAM_JUST_URL = 1;
27
28 static constexpr const int PARAM_URL_AND_OPTIONS_OR_CALLBACK = 2;
29
30 static constexpr const int PARAM_URL_AND_OPTIONS_AND_CALLBACK = 3;
31
32 namespace OHOS::NetStack {
RequestContext(napi_env env,EventManager * manager)33 RequestContext::RequestContext(napi_env env, EventManager *manager) : BaseContext(env, manager) {}
34
ParseParams(napi_value * params,size_t paramsCount)35 void RequestContext::ParseParams(napi_value *params, size_t paramsCount)
36 {
37 bool valid = CheckParamsType(params, paramsCount);
38 if (!valid) {
39 return;
40 }
41
42 if (paramsCount == PARAM_JUST_URL) {
43 options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
44 SetParseOK(true);
45 return;
46 }
47
48 if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
49 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
50 if (type == napi_function) {
51 options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]));
52 SetParseOK(SetCallback(params[1]) == napi_ok);
53 return;
54 }
55 if (type == napi_object) {
56 UrlAndOptions(params[0], params[1]);
57 return;
58 }
59 return;
60 }
61
62 if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
63 if (SetCallback(params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) != napi_ok) {
64 return;
65 }
66 UrlAndOptions(params[0], params[1]);
67 }
68 }
69
CheckParamsType(napi_value * params,size_t paramsCount)70 bool RequestContext::CheckParamsType(napi_value *params, size_t paramsCount)
71 {
72 if (paramsCount == PARAM_JUST_URL) {
73 // just url
74 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string;
75 }
76 if (paramsCount == PARAM_URL_AND_OPTIONS_OR_CALLBACK) {
77 // should be url, callback or url, options
78 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), params[1]);
79 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
80 (type == napi_function || type == napi_object);
81 }
82 if (paramsCount == PARAM_URL_AND_OPTIONS_AND_CALLBACK) {
83 // should be url options and callback
84 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string &&
85 NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object &&
86 NapiUtils::GetValueType(GetEnv(), params[PARAM_URL_AND_OPTIONS_AND_CALLBACK - 1]) == napi_function;
87 }
88 return false;
89 }
90
ParseNumberOptions(napi_value optionsValue)91 void RequestContext::ParseNumberOptions(napi_value optionsValue)
92 {
93 options.SetReadTimeout(NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_READ_TIMEOUT));
94 if (options.GetReadTimeout() == 0) {
95 options.SetReadTimeout(HttpConstant::DEFAULT_READ_TIMEOUT);
96 }
97
98 options.SetConnectTimeout(
99 NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_CONNECT_TIMEOUT));
100 if (options.GetConnectTimeout() == 0) {
101 options.SetConnectTimeout(HttpConstant::DEFAULT_CONNECT_TIMEOUT);
102 }
103
104 options.SetIfModifiedSince(
105 NapiUtils::GetUint32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_IF_MODIFIED_SINCE));
106 if (options.GetIfModifiedSince() == 0) {
107 options.SetIfModifiedSince(HttpConstant::DEFAULT_IF_MODIFIED_SINCE);
108 }
109
110 options.SetFixedLengthStreamingMode(
111 NapiUtils::GetInt32Property(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_FIXED_LENGTH_STREAMING_MODE));
112 if (options.GetFixedLengthStreamingMode() == 0) {
113 options.SetFixedLengthStreamingMode(HttpConstant::DEFAULT_FIXED_LENGTH_STREAMING_MODE);
114 }
115 }
116
ParseHeader(napi_value optionsValue)117 void RequestContext::ParseHeader(napi_value optionsValue)
118 {
119 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER)) {
120 return;
121 }
122 napi_value header = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER);
123 if (NapiUtils::GetValueType(GetEnv(), header) != napi_object) {
124 return;
125 }
126 auto names = NapiUtils::GetPropertyNames(GetEnv(), header);
127 std::for_each(names.begin(), names.end(), [header, this](const std::string &name) {
128 auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), header, name);
129 if (!value.empty()) {
130 options.SetHeader(CommonUtils::ToLower(name), value);
131 }
132 });
133 }
134
ParseExtraData(napi_value optionsValue)135 bool RequestContext::ParseExtraData(napi_value optionsValue)
136 {
137 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA)) {
138 NETSTACK_LOGI("no extraData");
139 return true;
140 }
141 napi_value extraData = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_EXTRA_DATA);
142
143 if (HttpExec::MethodForGet(options.GetMethod())) {
144 std::string url = options.GetUrl();
145 std::string param;
146 std::size_t index = url.find(HttpConstant::HTTP_URL_PARAM_START);
147 if (index != std::string::npos) {
148 param = url.substr(index + 1);
149 url = url.substr(0, index);
150 }
151
152 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
153 if (type == napi_string) {
154 std::string extraParam = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
155
156 options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
157 return true;
158 }
159 if (type != napi_object) {
160 return true;
161 }
162
163 std::string extraParam;
164 auto names = NapiUtils::GetPropertyNames(GetEnv(), extraData);
165 std::for_each(names.begin(), names.end(), [this, extraData, &extraParam](std::string name) {
166 auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), extraData, name);
167 NETSTACK_LOGI("url param name = ..., value = ...");
168 if (!name.empty() && !value.empty()) {
169 bool encodeName = HttpExec::EncodeUrlParam(name);
170 bool encodeValue = HttpExec::EncodeUrlParam(value);
171 if (encodeName || encodeValue) {
172 options.SetHeader(CommonUtils::ToLower(HttpConstant::HTTP_CONTENT_TYPE),
173 HttpConstant::HTTP_CONTENT_TYPE_URL_ENCODE);
174 }
175 extraParam +=
176 name + HttpConstant::HTTP_URL_NAME_VALUE_SEPARATOR + value + HttpConstant::HTTP_URL_PARAM_SEPARATOR;
177 }
178 });
179 if (!extraParam.empty()) {
180 extraParam = extraParam.substr(0, extraParam.size() - 1); // remove the last &
181 }
182
183 options.SetUrl(HttpExec::MakeUrl(url, param, extraParam));
184 return true;
185 }
186
187 if (HttpExec::MethodForPost(options.GetMethod())) {
188 return GetRequestBody(extraData);
189 }
190 return false;
191 }
192
GetRequestBody(napi_value extraData)193 bool RequestContext::GetRequestBody(napi_value extraData)
194 {
195 /* if body is empty, return false, or curl will wait for body */
196
197 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), extraData);
198 if (type == napi_string) {
199 auto body = NapiUtils::GetStringFromValueUtf8(GetEnv(), extraData);
200 if (body.empty()) {
201 return false;
202 }
203 options.SetBody(body.c_str(), body.size());
204 return true;
205 }
206
207 if (NapiUtils::ValueIsArrayBuffer(GetEnv(), extraData)) {
208 size_t length = 0;
209 void *data = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), extraData, &length);
210 if (data == nullptr) {
211 return false;
212 }
213 options.SetBody(data, length);
214 return true;
215 }
216
217 if (type == napi_object) {
218 std::string body = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), extraData));
219 if (body.empty()) {
220 return false;
221 }
222 options.SetBody(body.c_str(), body.length());
223 return true;
224 }
225
226 NETSTACK_LOGE("only support string arraybuffer and object");
227 return false;
228 }
229
UrlAndOptions(napi_value urlValue,napi_value optionsValue)230 void RequestContext::UrlAndOptions(napi_value urlValue, napi_value optionsValue)
231 {
232 options.SetUrl(NapiUtils::GetStringFromValueUtf8(GetEnv(), urlValue));
233
234 std::string method = NapiUtils::GetStringPropertyUtf8(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_METHOD);
235 if (method.empty()) {
236 method = HttpConstant::HTTP_METHOD_GET;
237 }
238 options.SetMethod(method);
239
240 ParseHeader(optionsValue);
241 ParseNumberOptions(optionsValue);
242
243 /* parse extra data here to recover header */
244
245 SetParseOK(ParseExtraData(optionsValue));
246 }
247 } // namespace OHOS::NetStack