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 "fetch_context.h"
17
18 #include "constant.h"
19 #include "fetch_exec.h"
20 #include "netstack_common_utils.h"
21 #include "netstack_log.h"
22 #include "napi_utils.h"
23
24 namespace OHOS::NetStack::Fetch {
FetchContext(napi_env env,EventManager * manager)25 FetchContext::FetchContext(napi_env env, EventManager *manager)
26 : BaseContext(env, manager), successCallback_(nullptr), failCallback_(nullptr), completeCallback_(nullptr)
27 {
28 }
29
ParseParams(napi_value * params,size_t paramsCount)30 void FetchContext::ParseParams(napi_value *params, size_t paramsCount)
31 {
32 SetNeedPromise(false);
33
34 bool valid = CheckParamsType(params, paramsCount);
35 if (!valid) {
36 NETSTACK_LOGE("fetch CheckParamsType failed");
37 return;
38 }
39
40 request.SetUrl(NapiUtils::GetStringPropertyUtf8(GetEnv(), params[0], FetchConstant::PARAM_KEY_URL));
41 request.SetMethod(NapiUtils::GetStringPropertyUtf8(GetEnv(), params[0], FetchConstant::PARAM_KEY_METHOD));
42 if (request.GetMethod().empty()) {
43 request.SetMethod(FetchConstant::HTTP_METHOD_GET);
44 }
45 if (NapiUtils::HasNamedProperty(GetEnv(), params[0], FetchConstant::PARAM_KEY_RESPONSE_TYPE)) {
46 responseType_ = NapiUtils::GetStringPropertyUtf8(GetEnv(), params[0], FetchConstant::PARAM_KEY_RESPONSE_TYPE);
47 }
48 ParseHeader(params[0]);
49 ParseData(params[0]);
50
51 napi_value success = NapiUtils::GetNamedProperty(GetEnv(), params[0], FetchConstant::PARAM_KEY_SUCCESS);
52 if (NapiUtils::GetValueType(GetEnv(), success) == napi_function) {
53 if (SetSuccessCallback(success) != napi_ok) {
54 NETSTACK_LOGE("SetSuccessCallback failed");
55 return;
56 }
57 }
58 napi_value fail = NapiUtils::GetNamedProperty(GetEnv(), params[0], FetchConstant::PARAM_KEY_FAIL);
59 if (NapiUtils::GetValueType(GetEnv(), fail) == napi_function) {
60 if (SetFailCallback(fail) != napi_ok) {
61 NETSTACK_LOGE("SetFailCallback failed");
62 return;
63 }
64 }
65 napi_value complete = NapiUtils::GetNamedProperty(GetEnv(), params[0], FetchConstant::PARAM_KEY_COMPLETE);
66 if (NapiUtils::GetValueType(GetEnv(), complete) == napi_function) {
67 if (SetCompleteCallback(complete) != napi_ok) {
68 NETSTACK_LOGE("SetCompleteCallback failed");
69 return;
70 }
71 }
72 NETSTACK_LOGI("fetch parse OK");
73 SetParseOK(true);
74 }
75
CheckParamsType(napi_value * params,size_t paramsCount)76 bool FetchContext::CheckParamsType(napi_value *params, size_t paramsCount)
77 {
78 if (paramsCount == 1) {
79 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object;
80 }
81 return false;
82 }
83
ParseHeader(napi_value optionsValue)84 void FetchContext::ParseHeader(napi_value optionsValue)
85 {
86 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, FetchConstant::PARAM_KEY_HEADER)) {
87 return;
88 }
89 napi_value header = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, FetchConstant::PARAM_KEY_HEADER);
90 if (NapiUtils::GetValueType(GetEnv(), header) != napi_object) {
91 return;
92 }
93 auto names = NapiUtils::GetPropertyNames(GetEnv(), header);
94 std::for_each(names.begin(), names.end(), [header, this](const std::string &name) {
95 auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), header, name);
96 if (!value.empty()) {
97 request.SetHeader(CommonUtils::ToLower(name), value);
98 }
99 });
100 }
101
ParseData(napi_value optionsValue)102 bool FetchContext::ParseData(napi_value optionsValue)
103 {
104 if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, FetchConstant::PARAM_KEY_DATA)) {
105 NETSTACK_LOGI("no extraData");
106 return true;
107 }
108 napi_value data = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, FetchConstant::PARAM_KEY_DATA);
109
110 if (FetchExec::MethodForGet(request.GetMethod())) {
111 return GetUrlParam(data);
112 }
113 if (FetchExec::MethodForPost(request.GetMethod())) {
114 return GetRequestBody(data);
115 }
116
117 NETSTACK_LOGE("ParseData failed, method is not supported %{public}s", request.GetMethod().c_str());
118 return false;
119 }
120
GetRequestBody(napi_value data)121 bool FetchContext::GetRequestBody(napi_value data)
122 {
123 /* if body is empty, return false, or curl will wait for body */
124
125 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), data);
126 if (type == napi_string) {
127 auto body = NapiUtils::GetStringFromValueUtf8(GetEnv(), data);
128 if (body.empty()) {
129 NETSTACK_LOGE("body napi_string is empty");
130 return false;
131 }
132 request.SetBody(body.c_str(), body.size());
133 return true;
134 }
135 if (type == napi_object) {
136 std::string body = NapiUtils::GetStringFromValueUtf8(GetEnv(), NapiUtils::JsonStringify(GetEnv(), data));
137 if (body.empty()) {
138 NETSTACK_LOGE("body napi_object is empty");
139 return false;
140 }
141 request.SetBody(body.c_str(), body.size());
142 return true;
143 }
144
145 NETSTACK_LOGE("Body just support string and object");
146 return false;
147 }
148
GetUrlParam(napi_value data)149 bool FetchContext::GetUrlParam(napi_value data)
150 {
151 std::string url = request.GetUrl();
152 if (url.empty()) {
153 NETSTACK_LOGE("url is empty!");
154 return false;
155 }
156
157 std::string param;
158 auto index = url.find(FetchConstant::HTTP_URL_PARAM_START);
159 if (index != std::string::npos) {
160 param = url.substr(index + 1);
161 url = url.substr(0, index);
162 }
163
164 napi_valuetype type = NapiUtils::GetValueType(GetEnv(), data);
165 if (type == napi_string) {
166 std::string extraParam = NapiUtils::GetStringFromValueUtf8(GetEnv(), data);
167
168 request.SetUrl(FetchExec::MakeUrl(url, param, extraParam));
169 return true;
170 }
171 if (type != napi_object) {
172 return true;
173 }
174
175 std::string extraParam;
176 auto names = NapiUtils::GetPropertyNames(GetEnv(), data);
177 std::for_each(names.begin(), names.end(), [this, data, &extraParam](std::string name) {
178 auto value = NapiUtils::GetStringPropertyUtf8(GetEnv(), data, name);
179 if (!name.empty() && !value.empty()) {
180 bool encodeName = FetchExec::EncodeUrlParam(name);
181 bool encodeValue = FetchExec::EncodeUrlParam(value);
182 if (encodeName || encodeValue) {
183 request.SetHeader(CommonUtils::ToLower(FetchConstant::HTTP_CONTENT_TYPE),
184 FetchConstant::HTTP_CONTENT_TYPE_URL_ENCODE);
185 }
186 extraParam +=
187 name + FetchConstant::HTTP_URL_NAME_VALUE_SEPARATOR + value + FetchConstant::HTTP_URL_PARAM_SEPARATOR;
188 }
189 });
190 if (!extraParam.empty()) {
191 extraParam.pop_back(); // remove the last &
192 }
193
194 request.SetUrl(FetchExec::MakeUrl(url, param, extraParam));
195 return true;
196 }
197
SetSuccessCallback(napi_value callback)198 napi_status FetchContext::SetSuccessCallback(napi_value callback)
199 {
200 if (successCallback_ != nullptr) {
201 (void)napi_delete_reference(GetEnv(), successCallback_);
202 }
203 return napi_create_reference(GetEnv(), callback, 1, &successCallback_);
204 }
205
SetFailCallback(napi_value callback)206 napi_status FetchContext::SetFailCallback(napi_value callback)
207 {
208 if (failCallback_ != nullptr) {
209 (void)napi_delete_reference(GetEnv(), failCallback_);
210 }
211 return napi_create_reference(GetEnv(), callback, 1, &failCallback_);
212 }
213
SetCompleteCallback(napi_value callback)214 napi_status FetchContext::SetCompleteCallback(napi_value callback)
215 {
216 if (completeCallback_ != nullptr) {
217 (void)napi_delete_reference(GetEnv(), completeCallback_);
218 }
219 return napi_create_reference(GetEnv(), callback, 1, &completeCallback_);
220 }
221
GetSuccessCallback() const222 napi_value FetchContext::GetSuccessCallback() const
223 {
224 if (successCallback_ == nullptr) {
225 return nullptr;
226 }
227 napi_value callback = nullptr;
228 NAPI_CALL(GetEnv(), napi_get_reference_value(GetEnv(), successCallback_, &callback));
229 return callback;
230 }
231
GetFailCallback() const232 napi_value FetchContext::GetFailCallback() const
233 {
234 if (failCallback_ == nullptr) {
235 return nullptr;
236 }
237 napi_value callback = nullptr;
238 NAPI_CALL(GetEnv(), napi_get_reference_value(GetEnv(), failCallback_, &callback));
239 return callback;
240 }
241
GetCompleteCallback() const242 napi_value FetchContext::GetCompleteCallback() const
243 {
244 if (completeCallback_ == nullptr) {
245 return nullptr;
246 }
247 napi_value callback = nullptr;
248 NAPI_CALL(GetEnv(), napi_get_reference_value(GetEnv(), completeCallback_, &callback));
249 return callback;
250 }
251
GetResponseType() const252 std::string FetchContext::GetResponseType() const
253 {
254 return responseType_;
255 }
256 } // namespace OHOS::NetStack::Fetch
257