• 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 #include "netstack_common_utils.h"
27 #include "trace_events.h"
28 
29 #define DECLARE_RESPONSE_CODE(code) \
30     DECLARE_NAPI_STATIC_PROPERTY(#code, NapiUtils::CreateUint32(env, static_cast<uint32_t>(ResponseCode::code)))
31 
32 #define DECLARE_REQUEST_METHOD(method) \
33     DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::method, NapiUtils::CreateStringUtf8(env, HttpConstant::method))
34 
35 #define DECLARE_HTTP_PROTOCOL(protocol) \
36     DECLARE_NAPI_STATIC_PROPERTY(#protocol, NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpProtocol::protocol)))
37 
38 namespace OHOS::NetStack::Http {
39 static constexpr const char *FLUSH_ASYNC_WORK_NAME = "ExecFlush";
40 
41 static constexpr const char *DELETE_ASYNC_WORK_NAME = "ExecDelete";
42 
43 static constexpr const char *HTTP_MODULE_NAME = "net.http";
44 
45 static thread_local uint64_t g_moduleId;
46 
47 static bool g_appIsAtomicService = false;
48 
49 static std::string g_appBundleName;
50 
51 static std::once_flag g_isAtomicServiceFlag;
52 
InitHttpModule(napi_env env,napi_value exports)53 napi_value HttpModuleExports::InitHttpModule(napi_env env, napi_value exports)
54 {
55     DefineHttpRequestClass(env, exports);
56     DefineHttpResponseCacheClass(env, exports);
57     InitHttpProperties(env, exports);
58     g_moduleId = NapiUtils::CreateUvHandlerQueue(env);
59     NapiUtils::SetEnvValid(env);
60     std::call_once(g_isAtomicServiceFlag, []() {
61         g_appIsAtomicService = CommonUtils::IsAtomicService(g_appBundleName);
62         NETSTACK_LOGI("IsAtomicService bundleName is %{public}s, isAtomicService is %{public}d",
63                       g_appBundleName.c_str(), g_appIsAtomicService);
64     });
65     auto envWrapper = new (std::nothrow)napi_env;
66     if (envWrapper == nullptr) {
67         return exports;
68     }
69     *envWrapper = env;
70     napi_add_env_cleanup_hook(env, NapiUtils::HookForEnvCleanup, envWrapper);
71     return exports;
72 }
73 
CreateHttp(napi_env env,napi_callback_info info)74 napi_value HttpModuleExports::CreateHttp(napi_env env, napi_callback_info info)
75 {
76     return ModuleTemplate::NewInstanceWithManagerWrapper(
77         env, info, INTERFACE_HTTP_REQUEST, [](napi_env, void *data, void *) {
78             NETSTACK_LOGD("http request handle is finalized");
79             auto wrapper = reinterpret_cast<EventManagerWrapper *>(data);
80             delete wrapper;
81         });
82 }
83 
CreateHttpResponseCache(napi_env env,napi_callback_info info)84 napi_value HttpModuleExports::CreateHttpResponseCache(napi_env env, napi_callback_info info)
85 {
86     napi_value thisVal = nullptr;
87     size_t paramsCount = MAX_PARAM_NUM;
88     napi_value params[MAX_PARAM_NUM] = {nullptr};
89     NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
90     if (paramsCount != 1 || NapiUtils::GetValueType(env, params[0]) != napi_number) {
91         CacheProxy::RunCache();
92     } else {
93         size_t size = NapiUtils::GetUint32FromValue(env, params[0]);
94         CacheProxy::RunCacheWithSize(size);
95     }
96 
97     return ModuleTemplate::NewInstanceNoManager(env, info, INTERFACE_HTTP_RESPONSE_CACHE, [](napi_env, void *, void *) {
98         NETSTACK_LOGI("http response cache handle is finalized");
99     });
100 }
101 
DefineHttpRequestClass(napi_env env,napi_value exports)102 void HttpModuleExports::DefineHttpRequestClass(napi_env env, napi_value exports)
103 {
104     std::initializer_list<napi_property_descriptor> properties = {
105         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_REQUEST, HttpRequest::Request),
106         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_REQUEST_IN_STREAM, HttpRequest::RequestInStream),
107         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_DESTROY, HttpRequest::Destroy),
108         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_ON, HttpRequest::On),
109         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_ONCE, HttpRequest::Once),
110         DECLARE_NAPI_FUNCTION(HttpRequest::FUNCTION_OFF, HttpRequest::Off),
111     };
112     ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_HTTP_REQUEST);
113 }
114 
DefineHttpResponseCacheClass(napi_env env,napi_value exports)115 void HttpModuleExports::DefineHttpResponseCacheClass(napi_env env, napi_value exports)
116 {
117     std::initializer_list<napi_property_descriptor> properties = {
118         DECLARE_NAPI_FUNCTION(HttpResponseCache::FUNCTION_FLUSH, HttpResponseCache::Flush),
119         DECLARE_NAPI_FUNCTION(HttpResponseCache::FUNCTION_DELETE, HttpResponseCache::Delete),
120     };
121     ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_HTTP_RESPONSE_CACHE);
122 }
123 
InitHttpProperties(napi_env env,napi_value exports)124 void HttpModuleExports::InitHttpProperties(napi_env env, napi_value exports)
125 {
126     std::initializer_list<napi_property_descriptor> properties = {
127         DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_HTTP, CreateHttp),
128         DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_HTTP_RESPONSE_CACHE, CreateHttpResponseCache),
129     };
130     NapiUtils::DefineProperties(env, exports, properties);
131 
132     InitRequestMethod(env, exports);
133     InitResponseCode(env, exports);
134     InitCertType(env, exports);
135     InitHttpProtocol(env, exports);
136     InitHttpDataType(env, exports);
137     InitTlsVersion(env, exports);
138     InitAddressFamily(env, exports);
139 }
140 
InitRequestMethod(napi_env env,napi_value exports)141 void HttpModuleExports::InitRequestMethod(napi_env env, napi_value exports)
142 {
143     std::initializer_list<napi_property_descriptor> properties = {
144         DECLARE_REQUEST_METHOD(HTTP_METHOD_OPTIONS), DECLARE_REQUEST_METHOD(HTTP_METHOD_GET),
145         DECLARE_REQUEST_METHOD(HTTP_METHOD_HEAD),    DECLARE_REQUEST_METHOD(HTTP_METHOD_POST),
146         DECLARE_REQUEST_METHOD(HTTP_METHOD_PUT),     DECLARE_REQUEST_METHOD(HTTP_METHOD_DELETE),
147         DECLARE_REQUEST_METHOD(HTTP_METHOD_TRACE),   DECLARE_REQUEST_METHOD(HTTP_METHOD_CONNECT),
148     };
149 
150     napi_value requestMethod = NapiUtils::CreateObject(env);
151     NapiUtils::DefineProperties(env, requestMethod, properties);
152 
153     NapiUtils::SetNamedProperty(env, exports, INTERFACE_REQUEST_METHOD, requestMethod);
154 }
155 
InitResponseCode(napi_env env,napi_value exports)156 void HttpModuleExports::InitResponseCode(napi_env env, napi_value exports)
157 {
158     std::initializer_list<napi_property_descriptor> properties = {
159         DECLARE_RESPONSE_CODE(OK),
160         DECLARE_RESPONSE_CODE(CREATED),
161         DECLARE_RESPONSE_CODE(ACCEPTED),
162         DECLARE_RESPONSE_CODE(NOT_AUTHORITATIVE),
163         DECLARE_RESPONSE_CODE(NO_CONTENT),
164         DECLARE_RESPONSE_CODE(RESET),
165         DECLARE_RESPONSE_CODE(PARTIAL),
166         DECLARE_RESPONSE_CODE(MULT_CHOICE),
167         DECLARE_RESPONSE_CODE(MOVED_PERM),
168         DECLARE_RESPONSE_CODE(MOVED_TEMP),
169         DECLARE_RESPONSE_CODE(SEE_OTHER),
170         DECLARE_RESPONSE_CODE(NOT_MODIFIED),
171         DECLARE_RESPONSE_CODE(USE_PROXY),
172         DECLARE_RESPONSE_CODE(BAD_REQUEST),
173         DECLARE_RESPONSE_CODE(UNAUTHORIZED),
174         DECLARE_RESPONSE_CODE(PAYMENT_REQUIRED),
175         DECLARE_RESPONSE_CODE(FORBIDDEN),
176         DECLARE_RESPONSE_CODE(NOT_FOUND),
177         DECLARE_RESPONSE_CODE(BAD_METHOD),
178         DECLARE_RESPONSE_CODE(NOT_ACCEPTABLE),
179         DECLARE_RESPONSE_CODE(PROXY_AUTH),
180         DECLARE_RESPONSE_CODE(CLIENT_TIMEOUT),
181         DECLARE_RESPONSE_CODE(CONFLICT),
182         DECLARE_RESPONSE_CODE(GONE),
183         DECLARE_RESPONSE_CODE(LENGTH_REQUIRED),
184         DECLARE_RESPONSE_CODE(PRECON_FAILED),
185         DECLARE_RESPONSE_CODE(ENTITY_TOO_LARGE),
186         DECLARE_RESPONSE_CODE(REQ_TOO_LONG),
187         DECLARE_RESPONSE_CODE(UNSUPPORTED_TYPE),
188         DECLARE_RESPONSE_CODE(RANGE_NOT_SATISFIABLE),
189         DECLARE_RESPONSE_CODE(INTERNAL_ERROR),
190         DECLARE_RESPONSE_CODE(NOT_IMPLEMENTED),
191         DECLARE_RESPONSE_CODE(BAD_GATEWAY),
192         DECLARE_RESPONSE_CODE(UNAVAILABLE),
193         DECLARE_RESPONSE_CODE(GATEWAY_TIMEOUT),
194         DECLARE_RESPONSE_CODE(VERSION),
195     };
196 
197     napi_value responseCode = NapiUtils::CreateObject(env);
198     NapiUtils::DefineProperties(env, responseCode, properties);
199 
200     NapiUtils::SetNamedProperty(env, exports, INTERFACE_RESPONSE_CODE, responseCode);
201 }
202 
InitTlsVersion(napi_env env,napi_value exports)203 void HttpModuleExports::InitTlsVersion(napi_env env, napi_value exports)
204 {
205     std::initializer_list<napi_property_descriptor> properties = {
206         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_0,
207             NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_0))),
208         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_1,
209             NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_1))),
210         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_2,
211             NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_2))),
212         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_3,
213             NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_3))),
214     };
215 
216     napi_value tlsVersion = NapiUtils::CreateObject(env);
217     NapiUtils::DefineProperties(env, tlsVersion, properties);
218 
219     NapiUtils::SetNamedProperty(env, exports, INTERFACE_TLS_VERSION, tlsVersion);
220 }
221 
InitHttpProtocol(napi_env env,napi_value exports)222 void HttpModuleExports::InitHttpProtocol(napi_env env, napi_value exports)
223 {
224     std::initializer_list<napi_property_descriptor> properties = {
225         DECLARE_HTTP_PROTOCOL(HTTP1_1),
226         DECLARE_HTTP_PROTOCOL(HTTP2),
227         DECLARE_HTTP_PROTOCOL(HTTP3),
228     };
229 
230     napi_value httpProtocol = NapiUtils::CreateObject(env);
231     NapiUtils::DefineProperties(env, httpProtocol, properties);
232 
233     NapiUtils::SetNamedProperty(env, exports, INTERFACE_HTTP_PROTOCOL, httpProtocol);
234 }
235 
InitCertType(napi_env env,napi_value exports)236 void HttpModuleExports::InitCertType(napi_env env, napi_value exports)
237 {
238     std::initializer_list<napi_property_descriptor> properties = {
239         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_CERT_TYPE_PEM,
240                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_CERT_TYPE_PEM)),
241         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_CERT_TYPE_DER,
242                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_CERT_TYPE_DER)),
243         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_CERT_TYPE_P12,
244                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_CERT_TYPE_P12)),
245     };
246     napi_value httpCertType = NapiUtils::CreateObject(env);
247     NapiUtils::DefineProperties(env, httpCertType, properties);
248     NapiUtils::SetNamedProperty(env, exports, INTERFACE_CERT_TYPE, httpCertType);
249 }
250 
InitHttpDataType(napi_env env,napi_value exports)251 void HttpModuleExports::InitHttpDataType(napi_env env, napi_value exports)
252 {
253     std::initializer_list<napi_property_descriptor> properties = {
254         DECLARE_NAPI_STATIC_PROPERTY("STRING",
255                                      NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpDataType::STRING))),
256         DECLARE_NAPI_STATIC_PROPERTY("OBJECT",
257                                      NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpDataType::OBJECT))),
258         DECLARE_NAPI_STATIC_PROPERTY("ARRAY_BUFFER",
259                                      NapiUtils::CreateUint32(env, static_cast<uint32_t>(HttpDataType::ARRAY_BUFFER))),
260     };
261     napi_value httpDataType = NapiUtils::CreateObject(env);
262     NapiUtils::DefineProperties(env, httpDataType, properties);
263     NapiUtils::SetNamedProperty(env, exports, INTERFACE_HTTP_DATA_TYPE, httpDataType);
264 }
265 
Request(napi_env env,napi_callback_info info)266 napi_value HttpModuleExports::HttpRequest::Request(napi_env env, napi_callback_info info)
267 {
268     return ModuleTemplate::InterfaceWithOutAsyncWorkWithManagerWrapper<RequestContext>(
269         env, info,
270         [](napi_env, napi_value, RequestContext *context) -> bool {
271 #if !HAS_NETMANAGER_BASE
272             if (!HttpExec::Initialize()) {
273                 return false;
274             }
275 #endif
276             context->GetTrace().Tracepoint(TraceEvents::FETCH);
277             context->SetModuleId(g_moduleId);
278             context->SetAtomicService(g_appIsAtomicService);
279             context->SetBundleName(g_appBundleName);
280             HttpExec::AsyncRunRequest(context);
281             return context->IsExecOK();
282         },
283         "Request", HttpAsyncWork::ExecRequest, HttpAsyncWork::RequestCallback);
284 }
285 
RequestInStream(napi_env env,napi_callback_info info)286 napi_value HttpModuleExports::HttpRequest::RequestInStream(napi_env env, napi_callback_info info)
287 {
288     return ModuleTemplate::InterfaceWithOutAsyncWorkWithManagerWrapper<RequestContext>(
289         env, info,
290         [](napi_env, napi_value, RequestContext *context) -> bool {
291 #if !HAS_NETMANAGER_BASE
292             if (!HttpExec::Initialize()) {
293                 return false;
294             }
295 #endif
296             context->GetTrace().Tracepoint(TraceEvents::FETCH);
297             context->SetModuleId(g_moduleId);
298             context->SetAtomicService(g_appIsAtomicService);
299             context->SetBundleName(g_appBundleName);
300             context->EnableRequestInStream();
301             HttpExec::AsyncRunRequest(context);
302             return true;
303         },
304         "RequestInStream", HttpAsyncWork::ExecRequest, HttpAsyncWork::RequestCallback);
305 }
306 
Destroy(napi_env env,napi_callback_info info)307 napi_value HttpModuleExports::HttpRequest::Destroy(napi_env env, napi_callback_info info)
308 {
309     napi_value thisVal = nullptr;
310     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
311     EventManagerWrapper *wrapper = nullptr;
312     auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
313     if (napiRet != napi_ok) {
314         NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napiRet);
315         return NapiUtils::GetUndefined(env);
316     }
317 
318     if (!wrapper) {
319         return NapiUtils::GetUndefined(env);
320     }
321     auto manager = wrapper->sharedManager;
322     if (!manager) {
323         return NapiUtils::GetUndefined(env);
324     }
325     if (manager->IsEventDestroy()) {
326         NETSTACK_LOGD("js object has been destroyed");
327         return NapiUtils::GetUndefined(env);
328     }
329     manager->SetEventDestroy(true);
330     manager->DeleteEventReference(env);
331     return NapiUtils::GetUndefined(env);
332 }
333 
On(napi_env env,napi_callback_info info)334 napi_value HttpModuleExports::HttpRequest::On(napi_env env, napi_callback_info info)
335 {
336     ModuleTemplate::OnManagerWrapper(
337         env, info, {ON_HEADERS_RECEIVE, ON_DATA_RECEIVE, ON_DATA_END, ON_DATA_RECEIVE_PROGRESS, ON_DATA_SEND_PROGRESS},
338         false);
339     return ModuleTemplate::OnManagerWrapper(env, info, {ON_HEADER_RECEIVE}, true);
340 }
341 
Once(napi_env env,napi_callback_info info)342 napi_value HttpModuleExports::HttpRequest::Once(napi_env env, napi_callback_info info)
343 {
344     return ModuleTemplate::OnceManagerWrapper(env, info, {ON_HEADER_RECEIVE, ON_HEADERS_RECEIVE}, false);
345 }
346 
Off(napi_env env,napi_callback_info info)347 napi_value HttpModuleExports::HttpRequest::Off(napi_env env, napi_callback_info info)
348 {
349     ModuleTemplate::OffManagerWrapper(
350         env, info, {ON_HEADERS_RECEIVE, ON_DATA_RECEIVE, ON_DATA_END, ON_DATA_RECEIVE_PROGRESS, ON_DATA_SEND_PROGRESS});
351     return ModuleTemplate::OffManagerWrapper(env, info, {ON_HEADER_RECEIVE});
352 }
353 
Flush(napi_env env,napi_callback_info info)354 napi_value HttpModuleExports::HttpResponseCache::Flush(napi_env env, napi_callback_info info)
355 {
356     return ModuleTemplate::InterfaceWithManagerWrapper<BaseContext>(
357         env, info, FLUSH_ASYNC_WORK_NAME, nullptr, HttpAsyncWork::ExecFlush, HttpAsyncWork::FlushCallback);
358 }
359 
Delete(napi_env env,napi_callback_info info)360 napi_value HttpModuleExports::HttpResponseCache::Delete(napi_env env, napi_callback_info info)
361 {
362     return ModuleTemplate::InterfaceWithManagerWrapper<BaseContext>(
363         env, info, DELETE_ASYNC_WORK_NAME, nullptr, HttpAsyncWork::ExecDelete, HttpAsyncWork::DeleteCallback);
364 }
365 
366 static napi_module g_httpModule = {
367     .nm_version = 1,
368     .nm_flags = 0,
369     .nm_filename = nullptr,
370     .nm_register_func = HttpModuleExports::InitHttpModule,
371     .nm_modname = HTTP_MODULE_NAME,
372     .nm_priv = nullptr,
373     .reserved = {nullptr},
374 };
375 
RegisterHttpModule(void)376 extern "C" __attribute__((constructor)) void RegisterHttpModule(void)
377 {
378     napi_module_register(&g_httpModule);
379 }
380 
InitAddressFamily(napi_env env,napi_value exports)381 void HttpModuleExports::InitAddressFamily(napi_env env, napi_value exports)
382 {
383     std::initializer_list<napi_property_descriptor> properties = {
384         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_ADDRESS_FAMILY_UNSPEC,
385                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_ADDRESS_FAMILY_UNSPEC)),
386         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_ADDRESS_FAMILY_ONLYV4,
387                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_ADDRESS_FAMILY_ONLYV4)),
388         DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::HTTP_ADDRESS_FAMILY_ONLYV6,
389                                      NapiUtils::CreateStringUtf8(env, HttpConstant::HTTP_ADDRESS_FAMILY_ONLYV6)),
390     };
391     napi_value httpAddressFamily = NapiUtils::CreateObject(env);
392     NapiUtils::DefineProperties(env, httpAddressFamily, properties);
393     NapiUtils::SetNamedProperty(env, exports, INTERFACE_ADDRESS_FAMILY, httpAddressFamily);
394 }
395 } // namespace OHOS::NetStack::Http
396