corecdtl 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +50 -0
- package/binding.gyp +49 -0
- package/native/http/core/http_core.cpp +395 -0
- package/native/http/core/http_core.h +90 -0
- package/native/http/core/http_scanner.cpp +1501 -0
- package/native/http/core/http_scanner.h +474 -0
- package/native/http/cpool/cpool.cpp +284 -0
- package/native/http/cpool/cpool.h +39 -0
- package/native/http/parser/asset_meta.cpp +31 -0
- package/native/http/parser/asset_meta.h +53 -0
- package/native/http/parser/asset_parser.cpp +52 -0
- package/native/http/parser/asset_parser.h +20 -0
- package/native/http/routes/route.h +85 -0
- package/native/http/routes/route_builder.cpp +161 -0
- package/native/http/routes/route_matching.cpp +267 -0
- package/native/http/routes/route_print.cpp +20 -0
- package/native/main.cpp +54 -0
- package/package.json +5 -11
- package/build/Release/hypernode.node +0 -0
package/CMakeLists.txt
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.9)
|
|
2
|
+
cmake_policy(SET CMP0042 NEW)
|
|
3
|
+
set (CMAKE_CXX_STANDARD 14)
|
|
4
|
+
if(NOT CMAKE_BUILD_TYPE)
|
|
5
|
+
set(CMAKE_BUILD_TYPE Release)
|
|
6
|
+
endif()
|
|
7
|
+
|
|
8
|
+
project(hypernode)
|
|
9
|
+
include_directories(${CMAKE_JS_INC})
|
|
10
|
+
include_directories(
|
|
11
|
+
${CMAKE_SOURCE_DIR}/native/include
|
|
12
|
+
${CMAKE_SOURCE_DIR}/native/http/core
|
|
13
|
+
${CMAKE_SOURCE_DIR}/native/http/routes
|
|
14
|
+
${CMAKE_SOURCE_DIR}/native/http/parser
|
|
15
|
+
${CMAKE_SOURCE_DIR}/native/http/cpool
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
include_directories(${CMAKE_SOURCE_DIR}/native/third_party/simdjson)
|
|
19
|
+
|
|
20
|
+
file(GLOB MAIN_SOURCE "native/main.cpp")
|
|
21
|
+
file(GLOB HTTP_SOURCES "native/http/core/*.cpp")
|
|
22
|
+
file(GLOB ROUTE_BUILDER_SOURCES "native/http/routes/*.cpp")
|
|
23
|
+
file(GLOB CHUNK_PROGRESSION_POOL_SOURCES "native/http/cpool/*.cpp")
|
|
24
|
+
file(GLOB PARSER_SOURCES "native/http/parser/*.cpp")
|
|
25
|
+
file(GLOB SIMDJSON_SOURCES "native/third_party/simdjson/*.cpp")
|
|
26
|
+
|
|
27
|
+
add_library(${PROJECT_NAME} SHARED
|
|
28
|
+
${MAIN_SOURCE}
|
|
29
|
+
${ROUTE_BUILDER_SOURCES}
|
|
30
|
+
${CHUNK_PROGRESSION_POOL_SOURCES}
|
|
31
|
+
${PARSER_SOURCES}
|
|
32
|
+
${HTTP_SOURCES}
|
|
33
|
+
${SIMDJSON_SOURCES}
|
|
34
|
+
${CMAKE_JS_SRC}
|
|
35
|
+
)
|
|
36
|
+
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
|
|
37
|
+
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})
|
|
38
|
+
|
|
39
|
+
# Include N-API wrappers
|
|
40
|
+
execute_process(
|
|
41
|
+
COMMAND node -p "require('node-addon-api').include"
|
|
42
|
+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
43
|
+
OUTPUT_VARIABLE NODE_ADDON_API_DIR
|
|
44
|
+
)
|
|
45
|
+
string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
|
|
46
|
+
string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
|
|
47
|
+
target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR})
|
|
48
|
+
|
|
49
|
+
# define NAPI_VERSION
|
|
50
|
+
add_definitions(-DNAPI_VERSION=3)
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "hypernode",
|
|
5
|
+
|
|
6
|
+
"sources": [
|
|
7
|
+
"native/main.cpp",
|
|
8
|
+
|
|
9
|
+
"native/http/core/*.cpp",
|
|
10
|
+
"native/http/routes/*.cpp",
|
|
11
|
+
"native/http/parser/*.cpp",
|
|
12
|
+
"native/http/cpool/*.cpp",
|
|
13
|
+
|
|
14
|
+
"native/third_party/simdjson/*.cpp"
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
"include_dirs": [
|
|
18
|
+
"<!(node -p \"require('node-addon-api').include\")",
|
|
19
|
+
"native/include",
|
|
20
|
+
"native/http/core",
|
|
21
|
+
"native/http/routes",
|
|
22
|
+
"native/http/parser",
|
|
23
|
+
"native/http/cpool",
|
|
24
|
+
"native/third_party/simdjson"
|
|
25
|
+
],
|
|
26
|
+
|
|
27
|
+
"defines": [
|
|
28
|
+
"NAPI_VERSION=3",
|
|
29
|
+
"NAPI_CPP_EXCEPTIONS"
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
"cflags_cc": [
|
|
33
|
+
"-std=c++17",
|
|
34
|
+
"-O3"
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
"conditions": [
|
|
38
|
+
["OS=='win'", {
|
|
39
|
+
"msvs_settings": {
|
|
40
|
+
"VCCLCompilerTool": {
|
|
41
|
+
"ExceptionHandling": 1,
|
|
42
|
+
"AdditionalOptions": ["/std:c++17"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}]
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#include "http_core.h"
|
|
2
|
+
#include <route.h>
|
|
3
|
+
#include "http_scanner.h"
|
|
4
|
+
#include <cpool.h>
|
|
5
|
+
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <napi.h>
|
|
8
|
+
#include <iostream>
|
|
9
|
+
|
|
10
|
+
__attribute__((always_inline))
|
|
11
|
+
void HttpCore::setMethodFlag(MethodType method) {
|
|
12
|
+
if (method >= M_HEAD && method <= M_OPTIONS)
|
|
13
|
+
this->m_methodFlags |= (1 << method);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
__attribute__((always_inline))
|
|
17
|
+
bool HttpCore::isMethodAllowed(MethodType method) {
|
|
18
|
+
if (method <= M_HEAD || method > M_OPTIONS) return false;
|
|
19
|
+
return this->m_methodFlags & (1 << method);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static inline bool isHttp11AtOffset(const char* curl, size_t curlLen, uint32_t* offset) {
|
|
23
|
+
if (!offset) return false;
|
|
24
|
+
uint32_t pos = *offset;
|
|
25
|
+
|
|
26
|
+
static constexpr const char* pattern = "HTTP/1.1";
|
|
27
|
+
static constexpr size_t plen = 8;
|
|
28
|
+
|
|
29
|
+
// sınır kontrolü (out of range)
|
|
30
|
+
if (pos + plen > curlLen) return false;
|
|
31
|
+
// memcmp — char by char karşılaştırmanın en hızlı yolu
|
|
32
|
+
if (memcmp(curl + pos, pattern, plen) != 0) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// eşleşti → offset ilerlet
|
|
37
|
+
*offset = pos + plen;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static inline MethodType scanHttpMethod(const char* curl, uint32_t* offset) {
|
|
42
|
+
const char* p = curl + *offset;
|
|
43
|
+
switch (*p) {
|
|
44
|
+
case 'G':
|
|
45
|
+
if (__builtin_expect(*(p+1) == 'E' && *(p+2) == 'T' &&
|
|
46
|
+
(*(p+3) == ' ' || *(p+3) == '\0'), 1)) {
|
|
47
|
+
*offset += 3;
|
|
48
|
+
return M_GET;
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
case 'H':
|
|
52
|
+
if (__builtin_expect(*(p+1) == 'E' && *(p+2) == 'A' && *(p+3) == 'D' &&
|
|
53
|
+
(*(p+4) == ' ' || *(p+4) == '\0'), 1)) {
|
|
54
|
+
*offset += 4;
|
|
55
|
+
return M_HEAD;
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'P':
|
|
59
|
+
switch (*(p+1)) {
|
|
60
|
+
case 'O':
|
|
61
|
+
if (__builtin_expect(*(p+2) == 'S' && *(p+3) == 'T' &&
|
|
62
|
+
(*(p+4) == ' ' || *(p+4) == '\0'), 1)) {
|
|
63
|
+
*offset += 4;
|
|
64
|
+
return M_POST;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case 'U':
|
|
68
|
+
if (__builtin_expect(*(p+2) == 'T' && (*(p+3) == ' ' || *(p+3) == '\0'), 1)) {
|
|
69
|
+
*offset += 3;
|
|
70
|
+
return M_PUT;
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
case 'A':
|
|
74
|
+
if (__builtin_expect(*(p+2) == 'T' && *(p+3) == 'C' && *(p+4) == 'H' &&
|
|
75
|
+
(*(p+5) == ' ' || *(p+5) == '\0'), 1)) {
|
|
76
|
+
*offset += 5;
|
|
77
|
+
return M_PATCH;
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
case 'D':
|
|
83
|
+
if (__builtin_expect(*(p+1) == 'E' && *(p+2) == 'L' && *(p+3) == 'E' &&
|
|
84
|
+
*(p+4) == 'T' && *(p+5) == 'E' &&
|
|
85
|
+
(*(p+6) == ' ' || *(p+6) == '\0'), 0)) {
|
|
86
|
+
*offset += 6;
|
|
87
|
+
return M_DELETE;
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
case 'O':
|
|
91
|
+
if (__builtin_expect(*(p+1) == 'P' && *(p+2) == 'T' && *(p+3) == 'I' &&
|
|
92
|
+
*(p+4) == 'O' && *(p+5) == 'N' && *(p+6) == 'S' &&
|
|
93
|
+
(*(p+7) == ' ' || *(p+7) == '\0'), 0)) {
|
|
94
|
+
*offset += 7;
|
|
95
|
+
return M_OPTIONS;
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return M_ERROR;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Napi::Function HttpCore::GetClass(Napi::Env env) {
|
|
104
|
+
return DefineClass(env, "HttpCore", {
|
|
105
|
+
InstanceMethod("registerRoutes", &HttpCore::RegisterRoutes),
|
|
106
|
+
InstanceMethod("scannerRouteFirst", &HttpCore::ScannerRouteFirst),
|
|
107
|
+
InstanceMethod("scannerHeader", &HttpCore::ScannerHeader),
|
|
108
|
+
InstanceMethod("printRouteTree", &HttpCore::PrintRouteTree),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
HttpCore::HttpCore(const Napi::CallbackInfo& info)
|
|
113
|
+
: Napi::ObjectWrap<HttpCore>(info) {
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
HttpCore::~HttpCore() {
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
RouteBuilder::EndpointParam HttpCore::makeParam(const std::string& name, RouteBuilder::ParamType type) {
|
|
122
|
+
return RouteBuilder::EndpointParam{ name, type };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
RouteBuilder::Endpoint HttpCore::makeEndpoint(const std::string& url, int vptr_table_index) {
|
|
126
|
+
RouteBuilder::Endpoint ep{};
|
|
127
|
+
std::string out;
|
|
128
|
+
std::vector<RouteBuilder::EndpointParam> params;
|
|
129
|
+
|
|
130
|
+
out.reserve(url.size());
|
|
131
|
+
|
|
132
|
+
for (size_t i = 0; i < url.size();) {
|
|
133
|
+
if (url[i] == ':' && (i == 0 || url[i - 1] == '/')) {
|
|
134
|
+
size_t start = i + 1;
|
|
135
|
+
size_t end = start;
|
|
136
|
+
|
|
137
|
+
while (end < url.size() && url[end] != '/' && url[end] != '?')
|
|
138
|
+
end++;
|
|
139
|
+
|
|
140
|
+
std::string paramName = url.substr(start, end - start);
|
|
141
|
+
|
|
142
|
+
out.push_back(':');
|
|
143
|
+
out += paramName;
|
|
144
|
+
params.push_back(makeParam(paramName, RouteBuilder::kString));
|
|
145
|
+
i = end;
|
|
146
|
+
} else {
|
|
147
|
+
out.push_back(url[i]);
|
|
148
|
+
++i;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
ep.url = strdup(out.c_str());
|
|
153
|
+
ep.params = std::move(params);
|
|
154
|
+
ep.vptr_table_index = vptr_table_index;
|
|
155
|
+
|
|
156
|
+
return ep;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
MethodType HttpCore::parserMethod(const std::string& method) {
|
|
160
|
+
if (method == "HEAD") return M_HEAD;
|
|
161
|
+
if (method == "GET") return M_GET;
|
|
162
|
+
if (method == "POST") return M_POST;
|
|
163
|
+
if (method == "PUT") return M_PUT;
|
|
164
|
+
if (method == "DELETE") return M_DELETE;
|
|
165
|
+
if (method == "PATCH") return M_PATCH;
|
|
166
|
+
if (method == "OPTIONS") return M_OPTIONS;
|
|
167
|
+
return M_ERROR;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
Napi::Value HttpCore::RegisterRoutes(const Napi::CallbackInfo& info) {
|
|
171
|
+
Napi::Env env = info.Env();
|
|
172
|
+
|
|
173
|
+
if (info.Length() < 1 || !info[0].IsArray()) {
|
|
174
|
+
Napi::TypeError::New(env, "Expected an array of route definitions").ThrowAsJavaScriptException();
|
|
175
|
+
return env.Null();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Napi::Array routes = info[0].As<Napi::Array>();
|
|
179
|
+
size_t routeCounts = routes.Length();
|
|
180
|
+
|
|
181
|
+
std::unique_ptr<std::vector<RouteBuilder::Endpoint>> methodEndpoints[METHOD_MAX_INDEX_COUNT];
|
|
182
|
+
for (int i = 0; i < METHOD_MAX_INDEX_COUNT; ++i) {
|
|
183
|
+
methodEndpoints[i] = std::make_unique<std::vector<RouteBuilder::Endpoint>>();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (size_t i = 0; i < routeCounts; i++) {
|
|
187
|
+
Napi::Value val = routes[i];
|
|
188
|
+
if (!val.IsObject()) continue;
|
|
189
|
+
|
|
190
|
+
Napi::Object routeObj = val.As<Napi::Object>();
|
|
191
|
+
|
|
192
|
+
std::string method = routeObj.Get("method").ToString();
|
|
193
|
+
std::string url = routeObj.Get("route").ToString();
|
|
194
|
+
int vptr_table_index = routeObj.Get("vptrTableIndex").As<Napi::Number>().Int32Value();
|
|
195
|
+
|
|
196
|
+
MethodType indexMethod = parserMethod(method);
|
|
197
|
+
if (indexMethod == M_ERROR) continue;
|
|
198
|
+
|
|
199
|
+
RouteBuilder::Endpoint ep = makeEndpoint(url, vptr_table_index);
|
|
200
|
+
|
|
201
|
+
methodEndpoints[static_cast<int>(indexMethod)]->push_back(std::move(ep));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (uint8_t index = 0; index < METHOD_MAX_INDEX_COUNT; ++index) {
|
|
205
|
+
auto& eps = methodEndpoints[index];
|
|
206
|
+
if (eps && !eps->empty()) {
|
|
207
|
+
auto routeBuilder = RouteBuilder::buildRouteTree(std::move(*eps));
|
|
208
|
+
|
|
209
|
+
// RouteBuilder::printRouteTree(routeBuilder); // For Debug
|
|
210
|
+
|
|
211
|
+
this->m_httpRouteMaps[index].route_node = routeBuilder;
|
|
212
|
+
setMethodFlag((MethodType)index);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return Napi::Number::New(env, routeCounts);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
Napi::Value HttpCore::ScannerRouteFirst(const Napi::CallbackInfo& info) {
|
|
220
|
+
Napi::Env env = info.Env();
|
|
221
|
+
|
|
222
|
+
auto curlBuf = info[0].As<Napi::Buffer<uint8_t>>();
|
|
223
|
+
uint8_t* curl = curlBuf.Data();
|
|
224
|
+
size_t curlLen = curlBuf.Length();
|
|
225
|
+
|
|
226
|
+
Napi::Object reqObj = info[1].As<Napi::Object>();
|
|
227
|
+
|
|
228
|
+
uint32_t main_offset = 0;
|
|
229
|
+
|
|
230
|
+
// ------------- SCAN METHOD ----------------
|
|
231
|
+
MethodType methodType = scanHttpMethod((const char*)curl, &main_offset);
|
|
232
|
+
|
|
233
|
+
if (!isMethodAllowed(methodType)) {
|
|
234
|
+
if (methodType == M_ERROR) {
|
|
235
|
+
uint32_t flags = FLAG_BAD_REQUEST;
|
|
236
|
+
reqObj.Set("retFlag", Napi::Number::New(env, flags));
|
|
237
|
+
return Napi::Number::New(env, -1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
uint32_t flags = FLAG_METHOD_NOT_ALLOWED;
|
|
241
|
+
if (methodType == M_OPTIONS)
|
|
242
|
+
flags |= FLAG_CORS_PREFLIGHT;
|
|
243
|
+
|
|
244
|
+
reqObj.Set("retFlag", Napi::Number::New(env, flags));
|
|
245
|
+
reqObj.Set("mainOffset", Napi::Number::New(env, main_offset));
|
|
246
|
+
return Napi::Number::New(env, -1);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
reqObj.Set("method", Napi::Number::New(env, (int)methodType));
|
|
250
|
+
|
|
251
|
+
main_offset += 1;
|
|
252
|
+
|
|
253
|
+
Napi::Array params = Napi::Array::New(env);
|
|
254
|
+
Napi::Object query = Napi::Object::New(env);
|
|
255
|
+
|
|
256
|
+
uint32_t query_limit = info[5].As<Napi::Number>();
|
|
257
|
+
// --------- MATCH ROUTE -------------
|
|
258
|
+
int routeId = RouteBuilder::matchUrl(env,
|
|
259
|
+
this->m_httpRouteMaps[methodType].route_node,
|
|
260
|
+
(const char*)curl,
|
|
261
|
+
curlLen,
|
|
262
|
+
&main_offset,
|
|
263
|
+
¶ms,
|
|
264
|
+
&query,
|
|
265
|
+
query_limit
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
if(routeId == -1) {
|
|
269
|
+
reqObj.Set("retFlag", Napi::Number::New(env, FLAG_NOT_FOUND));
|
|
270
|
+
return Napi::Number::New(env, -1);
|
|
271
|
+
} else if (routeId == -2) {
|
|
272
|
+
reqObj.Set("retFlag", Napi::Number::New(env, FLAG_REQUEST_QUERY_EXCEEDED));
|
|
273
|
+
return Napi::Number::New(env, -1);
|
|
274
|
+
} else if (routeId == -3) {
|
|
275
|
+
reqObj.Set("retFlag", Napi::Number::New(env, FLAG_REQUEST_URL_EXCEEDED));
|
|
276
|
+
return Napi::Number::New(env, -1);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
reqObj.Set("params", params);
|
|
280
|
+
reqObj.Set("query", query);
|
|
281
|
+
|
|
282
|
+
main_offset += 1;
|
|
283
|
+
// --------- HTTP VERSION VALIDATION ---------
|
|
284
|
+
bool ret = isHttp11AtOffset((const char*)curl, curlLen, &main_offset);
|
|
285
|
+
if (!ret) {
|
|
286
|
+
reqObj.Set("retFlag", Napi::Number::New(env, FLAG_HTTP_VERSION_UNSUPPORTED));
|
|
287
|
+
return Napi::Number::New(env, routeId);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
main_offset += 2;
|
|
291
|
+
// --------- HEADER SCANNER ---------
|
|
292
|
+
uint32_t currentHeaderSize = reqObj.Get("headerSize").As<Napi::Number>();
|
|
293
|
+
uint32_t maxHeaderNameSize = info[2].As<Napi::Number>();
|
|
294
|
+
uint32_t maxHeaderValueSize = info[3].As<Napi::Number>();
|
|
295
|
+
uint32_t maxHeaderSize = info[4].As<Napi::Number>();
|
|
296
|
+
Napi::Object headers = reqObj.Get("headers").As<Napi::Object>();
|
|
297
|
+
auto sOff = main_offset;
|
|
298
|
+
auto res = scanHeaders(env,
|
|
299
|
+
(const char*)curl, curlLen,
|
|
300
|
+
&main_offset,
|
|
301
|
+
maxHeaderSize,
|
|
302
|
+
|
|
303
|
+
maxHeaderSize,
|
|
304
|
+
maxHeaderValueSize,
|
|
305
|
+
currentHeaderSize,
|
|
306
|
+
|
|
307
|
+
methodType,
|
|
308
|
+
&headers);
|
|
309
|
+
reqObj.Set("retFlag", (int)res);
|
|
310
|
+
reqObj.Set("headerSize", Napi::Number::New(env, currentHeaderSize + main_offset - sOff));
|
|
311
|
+
// -------- SUCCESS -----------
|
|
312
|
+
reqObj.Set("mainOffset", Napi::Number::New(env, main_offset));
|
|
313
|
+
|
|
314
|
+
return Napi::Number::New(env, routeId);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
Napi::Value HttpCore::ScannerHeader(const Napi::CallbackInfo& info) {
|
|
318
|
+
Napi::Env env = info.Env();
|
|
319
|
+
|
|
320
|
+
auto curlBuf = info[0].As<Napi::Buffer<uint8_t>>();
|
|
321
|
+
uint8_t* curl = curlBuf.Data();
|
|
322
|
+
size_t curlLen = curlBuf.Length();
|
|
323
|
+
|
|
324
|
+
Napi::Object reqObj = info[1].As<Napi::Object>();
|
|
325
|
+
uint32_t maxHeaderNameSize = info[2].As<Napi::Number>();
|
|
326
|
+
uint32_t maxHeaderValueSize = info[3].As<Napi::Number>();
|
|
327
|
+
uint32_t maxHeaderSize = info[4].As<Napi::Number>();
|
|
328
|
+
|
|
329
|
+
uint32_t mainOff = reqObj.Get("mainOffset").As<Napi::Number>();
|
|
330
|
+
uint32_t currentHeaderSize = reqObj.Get("headerSize").As<Napi::Number>();
|
|
331
|
+
|
|
332
|
+
Napi::Object headers = reqObj.Get("headers").As<Napi::Object>();
|
|
333
|
+
uint32_t methodType = reqObj.Get("method").As<Napi::Number>();
|
|
334
|
+
auto sOff = mainOff;
|
|
335
|
+
auto res = scanHeaders(env,
|
|
336
|
+
(const char*)curl, curlLen,
|
|
337
|
+
&mainOff,
|
|
338
|
+
maxHeaderSize,
|
|
339
|
+
|
|
340
|
+
maxHeaderNameSize,
|
|
341
|
+
maxHeaderValueSize,
|
|
342
|
+
currentHeaderSize,
|
|
343
|
+
|
|
344
|
+
(MethodType)methodType,
|
|
345
|
+
&headers);
|
|
346
|
+
reqObj.Set("retFlag", (int)res);
|
|
347
|
+
reqObj.Set("headerSize", Napi::Number::New(env, currentHeaderSize + mainOff - sOff));
|
|
348
|
+
// -------- SUCCESS -----------
|
|
349
|
+
reqObj.Set("mainOffset", Napi::Number::New(env, mainOff));
|
|
350
|
+
|
|
351
|
+
return Napi::Number::New(env, 0);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
Napi::Value HttpCore::PrintRouteTree(const Napi::CallbackInfo& info) {
|
|
355
|
+
Napi::Env env = info.Env();
|
|
356
|
+
|
|
357
|
+
auto deepth = 4;
|
|
358
|
+
|
|
359
|
+
if (info.Length() == 1 || !info[0].IsNumber()) {
|
|
360
|
+
deepth = info[0].As<Napi::Number>();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
for (auto i = 0; i < METHOD_MAX_INDEX_COUNT; i++) {
|
|
364
|
+
std::string methodName = "";
|
|
365
|
+
switch (this->m_httpRouteMaps[i].method_type) {
|
|
366
|
+
case M_HEAD:
|
|
367
|
+
methodName = "HEAD";
|
|
368
|
+
break;
|
|
369
|
+
case M_GET:
|
|
370
|
+
methodName = "GET";
|
|
371
|
+
break;
|
|
372
|
+
case M_POST:
|
|
373
|
+
methodName = "POST";
|
|
374
|
+
break;
|
|
375
|
+
case M_PUT:
|
|
376
|
+
methodName = "PUT";
|
|
377
|
+
break;
|
|
378
|
+
case M_PATCH:
|
|
379
|
+
methodName = "PATCH";
|
|
380
|
+
break;
|
|
381
|
+
case M_DELETE:
|
|
382
|
+
methodName = "DELETE";
|
|
383
|
+
break;
|
|
384
|
+
case M_OPTIONS:
|
|
385
|
+
methodName = "OPTIONS";
|
|
386
|
+
break;
|
|
387
|
+
default:
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
std::cout << methodName << "\n";
|
|
391
|
+
RouteBuilder::printRouteTree(this->m_httpRouteMaps[i].route_node, deepth);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return Napi::Number::New(env, 0);
|
|
395
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <napi.h>
|
|
3
|
+
#include <route.h>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
using namespace std;
|
|
7
|
+
|
|
8
|
+
constexpr uint8_t METHOD_MAX_INDEX_COUNT = 7;
|
|
9
|
+
|
|
10
|
+
enum FlagBits : uint32_t {
|
|
11
|
+
FLAG_OK = 0x0000,
|
|
12
|
+
FLAG_BAD_REQUEST = 0x0001,
|
|
13
|
+
FLAG_METHOD_NOT_ALLOWED = 0x0002,
|
|
14
|
+
FLAG_NOT_FOUND = 0x0004,
|
|
15
|
+
FLAG_CORS_PREFLIGHT = 0x0008,
|
|
16
|
+
FLAG_HTTP_VERSION_UNSUPPORTED = 0x0010,
|
|
17
|
+
FLAG_CONTENT_LENGTH_TOO_LARGE = 0x0020,
|
|
18
|
+
FLAG_MISSING_HOST = 0x0040,
|
|
19
|
+
FLAG_HAS_BODY = 0x0080,
|
|
20
|
+
FLAG_INVALID_ARGUMENT = 0x0100,
|
|
21
|
+
FLAG_INVALID_HEADER = 0x0200,
|
|
22
|
+
FLAG_INVALID_HEADER_VALUE = 0X0300,
|
|
23
|
+
FLAG_INVALID_CONTENT_LENGTH = 0x0400,
|
|
24
|
+
FLAG_CONTENT_LENGTH_EXCEEDED = 0x0800,
|
|
25
|
+
FLAG_UNTERMINATED_HEADERS = 0x1000,
|
|
26
|
+
FLAG_MAX_HEADER_SIZE = 0X2000,
|
|
27
|
+
FLAG_MAX_HEADER_NAME_SIZE = 0X2100,
|
|
28
|
+
FLAG_MAX_HEADER_VALUE_SIZE = 0X2200,
|
|
29
|
+
FLAG_DUPLICATE_SINGLE_HEADER = 0X3000,
|
|
30
|
+
FLAG_REQUEST_QUERY_EXCEEDED = 0X4000,
|
|
31
|
+
FLAG_REQUEST_URL_EXCEEDED = 0X5000,
|
|
32
|
+
FLAG_SMUGGING_TE_CL = 0x6000
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
using MethodFlags = uint8_t;
|
|
36
|
+
|
|
37
|
+
enum MethodType : uint8_t {
|
|
38
|
+
M_HEAD,
|
|
39
|
+
M_GET,
|
|
40
|
+
M_POST,
|
|
41
|
+
M_PUT,
|
|
42
|
+
M_DELETE,
|
|
43
|
+
M_PATCH,
|
|
44
|
+
M_OPTIONS,
|
|
45
|
+
M_ERROR,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
enum HttpContextMode: uint8_t {
|
|
49
|
+
M_WEB,
|
|
50
|
+
M_API
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
struct HttpRoutes {
|
|
54
|
+
MethodType method_type;
|
|
55
|
+
shared_ptr<RouteBuilder::RouteNode> route_node; // Builded Route Node
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
class HttpCore : public Napi::ObjectWrap<HttpCore> {
|
|
59
|
+
public:
|
|
60
|
+
static Napi::Function GetClass(Napi::Env env);
|
|
61
|
+
HttpCore(const Napi::CallbackInfo& info);
|
|
62
|
+
~HttpCore();
|
|
63
|
+
|
|
64
|
+
// NAPI methods
|
|
65
|
+
Napi::Value RegisterRoutes(const Napi::CallbackInfo& info);
|
|
66
|
+
Napi::Value ScannerRouteFirst(const Napi::CallbackInfo& info);
|
|
67
|
+
Napi::Value ScannerHeader(const Napi::CallbackInfo& info);
|
|
68
|
+
Napi::Value PrintRouteTree(const Napi::CallbackInfo& info);
|
|
69
|
+
|
|
70
|
+
private:
|
|
71
|
+
HttpContextMode m_httpContextMode;
|
|
72
|
+
MethodFlags m_methodFlags = 0;
|
|
73
|
+
HttpRoutes m_httpRouteMaps[METHOD_MAX_INDEX_COUNT] = {
|
|
74
|
+
{ M_HEAD, nullptr },
|
|
75
|
+
{ M_GET, nullptr },
|
|
76
|
+
{ M_POST, nullptr },
|
|
77
|
+
{ M_PUT, nullptr },
|
|
78
|
+
{ M_DELETE, nullptr },
|
|
79
|
+
{ M_PATCH, nullptr },
|
|
80
|
+
{ M_OPTIONS, nullptr },
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// helpers
|
|
84
|
+
MethodType parserMethod(const std::string& method);
|
|
85
|
+
void setMethodFlag(MethodType method);
|
|
86
|
+
bool isMethodAllowed(MethodType method);
|
|
87
|
+
|
|
88
|
+
RouteBuilder::Endpoint makeEndpoint(const std::string& url, int vptr_table_index);
|
|
89
|
+
RouteBuilder::EndpointParam makeParam(const std::string& name, RouteBuilder::ParamType type);
|
|
90
|
+
};
|