• 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 "http_module.h"
17 
18 #include "cache_proxy.h"
19 #include "constant.h"
20 #include "event_list.h"
21 #include "http_async_work.h"
22 #include "http_exec.h"
23 
24 #include "module_template.h"
25 #include "netstack_log.h"
26 
27 #define DECLARE_RESPONSE_CODE(code) \
28     DECLARE_NAPI_STATIC_PROPERTY(#code, NapiUtils::CreateUint32(env, static_cast<uint32_t>(ResponseCode::code)))
29 
30 #define DECLARE_REQUEST_METHOD(method) \
31     DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::method, NapiUtils::CreateStringUtf8(env, HttpConstant::method))
32 
33 #define DECLARE_HTTP_PROTOCOL(protocol) \
34     DECLARE_NAPI_STATIC_PROPERTY(#protocol, NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpProtocol::protocol)))
35 
36 namespace OHOS::NetStack::Http {
37 static constexpr const char *FLUSH_ASYNC_WORK_NAME = "ExecFlush";
38 
39 #ifdef MAC_PLATFORM
40 static constexpr const char *REQUEST_ASYNC_WORK_NAME = "ExecRequest";
41 #endif
42 
43 static constexpr const char *DELETE_ASYNC_WORK_NAME = "ExecDelete";
44 
45 static constexpr const char *HTTP_MODULE_NAME = "net.http";
46 
InitHttpModule(napi_env env,napi_value exports)47 napi_value HttpModuleExports::InitHttpModule(napi_env env, napi_value exports)
48 {
49     DefineHttpRequestClass(env, exports);
50     DefineHttpResponseCacheClass(env, exports);
51     InitHttpProperties(env, exports);
52 
53     return exports;
54 }
55 
CreateHttp(napi_env env,napi_callback_info info)56 napi_value HttpModuleExports::CreateHttp(napi_env env, napi_callback_info info)
57 {
58     return ModuleTemplate::NewInstance(env, info, INTERFACE_HTTP_REQUEST, [](napi_env, void *data, void *) {
59         NETSTACK_LOGD("http request handle is finalized");
60         auto manager = reinterpret_cast<EventManager *>(data);
61         if (manager != nullptr) {
62             EventManager::SetInvalid(manager);
63         }
64     });
65 }
66 
CreateHttpResponseCache(napi_env env,napi_callback_info info)67 napi_value HttpModuleExports::CreateHttpResponseCache(napi_env env, napi_callback_info info)
68 {
69     napi_value thisVal = nullptr;
70     size_t paramsCount = MAX_PARAM_NUM;
71     napi_value params[MAX_PARAM_NUM] = {nullptr};
72     NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
73     if (paramsCount != 1 || NapiUtils::GetValueType(env, params[0]) != napi_number) {
74         CacheProxy::RunCache();
75     } else {
76         size_t size = NapiUtils::GetUint32FromValue(env, params[0]);
77         CacheProxy::RunCacheWithSize(size);
78     }
79 
80     return ModuleTemplate::NewInstanceNoManager(env, info, INTERFACE_HTTP_RESPONSE_CACHE, [](napi_env, void *, void *) {
81         NETSTACK_LOGI("http response cache handle is finalized");
82     });
83 }
84 
DefineHttpRequestClass(napi_env env,napi_value exports)85 void HttpModuleExports::DefineHttpRequestClass(napi_env env, napi_value exports)
86 {
87     std::initializer_list<napi_property_descriptor> properties = {
88         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_REQUEST, HttpRequest::Request),
89         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_REQUEST_IN_STREAM, HttpRequest::RequestInStream),
90         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_DESTROY, HttpRequest::Destroy),
91         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_ON, HttpRequest::On),
92         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_ONCE, HttpRequest::Once),
93         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_OFF, HttpRequest::Off),
94     };
95     ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_HTTP_REQUEST);
96 }
97 
DefineHttpResponseCacheClass(napi_env env,napi_value exports)98 void HttpModuleExports::DefineHttpResponseCacheClass(napi_env env, napi_value exports)
99 {
100     std::initializer_list<napi_property_descriptor> properties = {
101         DECLARE_NAPI_FUNCTION(HttpResponseCache::FUNCTION_FLUSH, HttpResponseCache::Flush),
102         DECLARE_NAPI_FUNCTION(HttpResponseCache::FUNCTION_DELETE, HttpResponseCache::Delete),
103     };
104     ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_HTTP_RESPONSE_CACHE);
105 }
106 
InitHttpProperties(napi_env env,napi_value exports)107 void HttpModuleExports::InitHttpProperties(napi_env env, napi_value exports)
108 {
109     std::initializer_list<napi_property_descriptor> properties = {
110         DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_HTTP, CreateHttp),
111         DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_HTTP_RESPONSE_CACHE, CreateHttpResponseCache),
112     };
113     NapiUtils::DefineProperties(env, exports, properties);
114 
115     InitRequestMethod(env, exports);
116     InitResponseCode(env, exports);
117     InitCertType(env, exports);
118     InitHttpProtocol(env, exports);
119     InitHttpDataType(env, exports);
120 }
121 
InitRequestMethod(napi_env env,napi_value exports)122 void HttpModuleExports::InitRequestMethod(napi_env env, napi_value exports)
123 {
124     std::initializer_list<napi_property_descriptor> properties = {
125         DECLARE_REQUEST_METHOD(HTTP_METHOD_OPTIONS), DECLARE_REQUEST_METHOD(HTTP_METHOD_GET),
126         DECLARE_REQUEST_METHOD(HTTP_METHOD_HEAD),    DECLARE_REQUEST_METHOD(HTTP_METHOD_POST),
127         DECLARE_REQUEST_METHOD(HTTP_METHOD_PUT),     DECLARE_REQUEST_METHOD(HTTP_METHOD_DELETE),
128         DECLARE_REQUEST_METHOD(HTTP_METHOD_TRACE),   DECLARE_REQUEST_METHOD(HTTP_METHOD_CONNECT),
129     };
130 
131     napi_value requestMethod = NapiUtils::CreateObject(env);
132     NapiUtils::DefineProperties(env, requestMethod, properties);
133 
134     NapiUtils::SetNamedProperty(env, exports, INTERFACE_REQUEST_METHOD, requestMethod);
135 }
136 
InitResponseCode(napi_env env,napi_value exports)137 void HttpModuleExports::InitResponseCode(napi_env env, napi_value exports)
138 {
139     std::initializer_list<napi_property_descriptor> properties = {
140         DECLARE_RESPONSE_CODE(OK),
141         DECLARE_RESPONSE_CODE(CREATED),
142         DECLARE_RESPONSE_CODE(ACCEPTED),
143         DECLARE_RESPONSE_CODE(NOT_AUTHORITATIVE),
144         DECLARE_RESPONSE_CODE(NO_CONTENT),
145         DECLARE_RESPONSE_CODE(RESET),
146         DECLARE_RESPONSE_CODE(PARTIAL),
147         DECLARE_RESPONSE_CODE(MULT_CHOICE),
148         DECLARE_RESPONSE_CODE(MOVED_PERM),
149         DECLARE_RESPONSE_CODE(MOVED_TEMP),
150         DECLARE_RESPONSE_CODE(SEE_OTHER),
151         DECLARE_RESPONSE_CODE(NOT_MODIFIED),
152         DECLARE_RESPONSE_CODE(USE_PROXY),
153         DECLARE_RESPONSE_CODE(BAD_REQUEST),
154         DECLARE_RESPONSE_CODE(UNAUTHORIZED),
155         DECLARE_RESPONSE_CODE(PAYMENT_REQUIRED),
156         DECLARE_RESPONSE_CODE(FORBIDDEN),
157         DECLARE_RESPONSE_CODE(NOT_FOUND),
158         DECLARE_RESPONSE_CODE(BAD_METHOD),
159         DECLARE_RESPONSE_CODE(NOT_ACCEPTABLE),
160         DECLARE_RESPONSE_CODE(PROXY_AUTH),
161         DECLARE_RESPONSE_CODE(CLIENT_TIMEOUT),
162         DECLARE_RESPONSE_CODE(CONFLICT),
163         DECLARE_RESPONSE_CODE(GONE),
164         DECLARE_RESPONSE_CODE(LENGTH_REQUIRED),
165         DECLARE_RESPONSE_CODE(PRECON_FAILED),
166         DECLARE_RESPONSE_CODE(ENTITY_TOO_LARGE),
167         DECLARE_RESPONSE_CODE(REQ_TOO_LONG),
168         DECLARE_RESPONSE_CODE(UNSUPPORTED_TYPE),
169         DECLARE_RESPONSE_CODE(INTERNAL_ERROR),
170         DECLARE_RESPONSE_CODE(NOT_IMPLEMENTED),
171         DECLARE_RESPONSE_CODE(BAD_GATEWAY),
172         DECLARE_RESPONSE_CODE(UNAVAILABLE),
173         DECLARE_RESPONSE_CODE(GATEWAY_TIMEOUT),
174         DECLARE_RESPONSE_CODE(VERSION),
175     };
176 
177     napi_value responseCode = NapiUtils::CreateObject(env);
178     NapiUtils::DefineProperties(env, responseCode, properties);
179 
180     NapiUtils::SetNamedProperty(env, exports, INTERFACE_RESPONSE_CODE, responseCode);
181 }
182 
InitHttpProtocol(napi_env env,napi_value exports)183 void HttpModuleExports::InitHttpProtocol(napi_env env, napi_value exports)
184 {
185     std::initializer_list<napi_property_descriptor> properties = {
186         DECLARE_HTTP_PROTOCOL(HTTP1_1),
187         DECLARE_HTTP_PROTOCOL(HTTP2),
188         DECLARE_HTTP_PROTOCOL(HTTP3),
189     };
190 
191     napi_value httpProtocol = NapiUtils::CreateObject(env);
192     NapiUtils::DefineProperties(env, httpProtocol, properties);
193 
194     NapiUtils::SetNamedProperty(env, exports, INTERFACE_HTTP_PROTOCOL, httpProtocol);
195 }
196 
InitCertType(napi_env env,napi_value exports)197 void HttpModuleExports::InitCertType(napi_env env, napi_value exports)
198 {
199     std::initializer_list<napi_property_descriptor> properties = {
200         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_CERT_TYPE_PEM,
201                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_CERT_TYPE_PEM)),
202         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_CERT_TYPE_DER,
203                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_CERT_TYPE_DER)),
204         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_CERT_TYPE_P12,
205                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_CERT_TYPE_P12)),
206     };
207     napi_value httpCertType = NapiUtils::CreateObject(env);
208     NapiUtils::DefineProperties(env, httpCertType, properties);
209     NapiUtils::SetNamedProperty(env, exports, INTERFACE_CERT_TYPE, httpCertType);
210 }
211 
InitHttpDataType(napi_env env,napi_value exports)212 void HttpModuleExports::InitHttpDataType(napi_env env, napi_value exports)
213 {
214     std::initializer_list<napi_property_descriptor> properties = {
215         DECLARE_NAPI_STATIC_PROPERTY("STRING",
216                                      NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpDataType::STRING))),
217         DECLARE_NAPI_STATIC_PROPERTY("OBJECT",
218                                      NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpDataType::OBJECT))),
219         DECLARE_NAPI_STATIC_PROPERTY("ARRAY_BUFFER",
220                                      NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpDataType::ARRAY_BUFFER))),
221     };
222     napi_value httpDataType = NapiUtils::CreateObject(env);
223     NapiUtils::DefineProperties(env, httpDataType, properties);
224     NapiUtils::SetNamedProperty(env, exports, INTERFACE_HTTP_DATA_TYPE, httpDataType);
225 }
226 
Request(napi_env env,napi_callback_info info)227 napi_value HttpModuleExports::HttpRequest::Request(napi_env env, napi_callback_info info)
228 {
229 #ifndef MAC_PLATFORM
230     return ModuleTemplate::InterfaceWithOutAsyncWork<RequestContext>(
231         env, info,
232         [](napi_env, napi_value, RequestContext *context) -> bool {
233             if (!HttpExec::Initialize()) {
234                 return false;
235             }
236             HttpExec::AsyncRunRequest(context);
237             return context->IsExecOK();
238         },
239         "Request", HttpAsyncWork::ExecRequest, HttpAsyncWork::RequestCallback);
240 #else
241     return ModuleTemplate::Interface<RequestContext>(
242         env, info, REQUEST_ASYNC_WORK_NAME,
243         [](napi_env, napi_value, RequestContext *) -> bool { return HttpExec::Initialize(); },
244         HttpAsyncWork::ExecRequest, HttpAsyncWork::RequestCallback);
245 #endif
246 }
247 
RequestInStream(napi_env env,napi_callback_info info)248 napi_value HttpModuleExports::HttpRequest::RequestInStream(napi_env env, napi_callback_info info)
249 {
250 #ifndef MAC_PLATFORM
251     return ModuleTemplate::InterfaceWithOutAsyncWork<RequestContext>(
252         env, info,
253         [](napi_env, napi_value, RequestContext *context) -> bool {
254             if (!HttpExec::Initialize()) {
255                 return false;
256             }
257             context->EnableRequestInStream();
258             HttpExec::AsyncRunRequest(context);
259             return true;
260         },
261         "RequestInStream", HttpAsyncWork::ExecRequest, HttpAsyncWork::RequestCallback);
262 #else
263     return ModuleTemplate::Interface<RequestContext>(
264         env, info, REQUEST_ASYNC_WORK_NAME,
265         [](napi_env, napi_value, RequestContext *) -> bool { return HttpExec::Initialize(); },
266         HttpAsyncWork::ExecRequest, HttpAsyncWork::RequestCallback);
267 #endif
268 }
269 
Destroy(napi_env env,napi_callback_info info)270 napi_value HttpModuleExports::HttpRequest::Destroy(napi_env env, napi_callback_info info)
271 {
272     napi_value thisVal = nullptr;
273     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
274     EventManager *manager = nullptr;
275     auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&manager));
276     if (napi_ret != napi_ok) {
277         NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
278         return NapiUtils::GetUndefined(env);
279     }
280 
281     if (manager->IsEventDestroy()) {
282         NETSTACK_LOGD("js object has been destroyed");
283         return NapiUtils::GetUndefined(env);
284     }
285     manager->SetEventDestroy(true);
286     manager->DeleteEventReference(env);
287     return NapiUtils::GetUndefined(env);
288 }
289 
On(napi_env env,napi_callback_info info)290 napi_value HttpModuleExports::HttpRequest::On(napi_env env, napi_callback_info info)
291 {
292     ModuleTemplate::On(env, info,
293         { ON_HEADERS_RECEIVE, ON_DATA_RECEIVE, ON_DATA_END, ON_DATA_RECEIVE_PROGRESS, ON_DATA_SEND_PROGRESS }, false);
294     return ModuleTemplate::On(env, info, { ON_HEADER_RECEIVE }, true);
295 }
296 
Once(napi_env env,napi_callback_info info)297 napi_value HttpModuleExports::HttpRequest::Once(napi_env env, napi_callback_info info)
298 {
299     return ModuleTemplate::Once(env, info, {ON_HEADER_RECEIVE, ON_HEADERS_RECEIVE}, false);
300 }
301 
Off(napi_env env,napi_callback_info info)302 napi_value HttpModuleExports::HttpRequest::Off(napi_env env, napi_callback_info info)
303 {
304     ModuleTemplate::Off(env, info,
305         { ON_HEADERS_RECEIVE, ON_DATA_RECEIVE, ON_DATA_END, ON_DATA_RECEIVE_PROGRESS, ON_DATA_SEND_PROGRESS });
306     return ModuleTemplate::Off(env, info, { ON_HEADER_RECEIVE });
307 }
308 
Flush(napi_env env,napi_callback_info info)309 napi_value HttpModuleExports::HttpResponseCache::Flush(napi_env env, napi_callback_info info)
310 {
311     return ModuleTemplate::Interface<BaseContext>(env, info, FLUSH_ASYNC_WORK_NAME, nullptr, HttpAsyncWork::ExecFlush,
312                                                   HttpAsyncWork::FlushCallback);
313 }
314 
Delete(napi_env env,napi_callback_info info)315 napi_value HttpModuleExports::HttpResponseCache::Delete(napi_env env, napi_callback_info info)
316 {
317     return ModuleTemplate::Interface<BaseContext>(env, info, DELETE_ASYNC_WORK_NAME, nullptr, HttpAsyncWork::ExecDelete,
318                                                   HttpAsyncWork::DeleteCallback);
319 }
320 
321 static napi_module g_httpModule = {
322     .nm_version = 1,
323     .nm_flags = 0,
324     .nm_filename = nullptr,
325     .nm_register_func = HttpModuleExports::InitHttpModule,
326     .nm_modname = HTTP_MODULE_NAME,
327     .nm_priv = nullptr,
328     .reserved = {nullptr},
329 };
330 
RegisterHttpModule(void)331 extern "C" __attribute__((constructor)) void RegisterHttpModule(void)
332 {
333     napi_module_register(&g_httpModule);
334 }
335 } // namespace OHOS::NetStack::Http
336