• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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