@maiyunnet/kebab 3.1.17 → 3.1.19
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/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/net.d.ts +7 -2
- package/lib/net.js +10 -6
- package/lib/ws.d.ts +4 -0
- package/lib/ws.js +10 -2
- package/package.json +1 -1
- package/sys/child.js +54 -41
- package/sys/ctr.d.ts +2 -2
- package/sys/route.js +3 -3
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '3.1.
|
|
9
|
+
export const VER = '3.1.19';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/net.d.ts
CHANGED
|
@@ -74,11 +74,12 @@ export declare function resetCookieSession(cookie: Record<string, ICookie>): voi
|
|
|
74
74
|
*/
|
|
75
75
|
export declare function getFormData(): fd.FormData;
|
|
76
76
|
/**
|
|
77
|
-
* --- 剔除不代理的 header ---
|
|
77
|
+
* --- 剔除不代理的 header,返回新的 header ---
|
|
78
78
|
* @param headers 剔除前的 header
|
|
79
79
|
* @param res 直接设置头部而不返回,可置空
|
|
80
|
+
* @param filter 返回 true 则留下
|
|
80
81
|
*/
|
|
81
|
-
export declare function filterProxyHeaders(headers: http.IncomingHttpHeaders | http2.IncomingHttpHeaders | THttpHeaders, res?: http2.Http2ServerResponse | http.ServerResponse): Record<string, string | string[]>;
|
|
82
|
+
export declare function filterProxyHeaders(headers: http.IncomingHttpHeaders | http2.IncomingHttpHeaders | THttpHeaders, res?: http2.Http2ServerResponse | http.ServerResponse, filter?: (h: string) => boolean): Record<string, string | string[]>;
|
|
82
83
|
/**
|
|
83
84
|
* --- 正向 mproxy 代理,注意提前处理不要自动处理 post 数据,读取 get 的 url 为实际请求地址 ---
|
|
84
85
|
* --- get: url, auth ---
|
|
@@ -129,6 +130,8 @@ export interface IMproxyOptions {
|
|
|
129
130
|
'hosts'?: Record<string, string>;
|
|
130
131
|
'local'?: string;
|
|
131
132
|
'headers'?: THttpHeaders;
|
|
133
|
+
/** --- 过滤 header,返回 true 则留下 --- */
|
|
134
|
+
filter?: (h: string) => boolean;
|
|
132
135
|
/** --- 默认为 default --- */
|
|
133
136
|
'reuse'?: string;
|
|
134
137
|
}
|
|
@@ -140,6 +143,8 @@ export interface IRproxyOptions {
|
|
|
140
143
|
'hosts'?: Record<string, string>;
|
|
141
144
|
'local'?: string;
|
|
142
145
|
'headers'?: THttpHeaders;
|
|
146
|
+
/** --- 过滤 header,返回 true 则留下 --- */
|
|
147
|
+
filter?: (h: string) => boolean;
|
|
143
148
|
/** --- 正向 mproxy 代理,url 如 https://xxx/abc --- */
|
|
144
149
|
'mproxy'?: {
|
|
145
150
|
'url': string;
|
package/lib/net.js
CHANGED
|
@@ -434,11 +434,12 @@ const proxyContinueHeaders = [
|
|
|
434
434
|
'transfer-encoding'
|
|
435
435
|
];
|
|
436
436
|
/**
|
|
437
|
-
* --- 剔除不代理的 header ---
|
|
437
|
+
* --- 剔除不代理的 header,返回新的 header ---
|
|
438
438
|
* @param headers 剔除前的 header
|
|
439
439
|
* @param res 直接设置头部而不返回,可置空
|
|
440
|
+
* @param filter 返回 true 则留下
|
|
440
441
|
*/
|
|
441
|
-
export function filterProxyHeaders(headers, res) {
|
|
442
|
+
export function filterProxyHeaders(headers, res, filter) {
|
|
442
443
|
const heads = {};
|
|
443
444
|
for (const h in headers) {
|
|
444
445
|
if (proxyContinueHeaders.includes(h)) {
|
|
@@ -451,6 +452,9 @@ export function filterProxyHeaders(headers, res) {
|
|
|
451
452
|
if (v === undefined) {
|
|
452
453
|
continue;
|
|
453
454
|
}
|
|
455
|
+
if (filter && !filter(h)) {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
454
458
|
if (res) {
|
|
455
459
|
res.setHeader(h, v);
|
|
456
460
|
continue;
|
|
@@ -482,14 +486,14 @@ export async function mproxy(ctr, auth, opt = {}) {
|
|
|
482
486
|
}
|
|
483
487
|
opt.method = req.method ?? 'GET';
|
|
484
488
|
opt.headers ??= {};
|
|
485
|
-
Object.assign(
|
|
489
|
+
Object.assign(filterProxyHeaders(req.headers, undefined, opt.filter), opt.headers);
|
|
486
490
|
// --- 发起请求 ---
|
|
487
491
|
const rres = await request(get['url'], req, opt);
|
|
488
492
|
if (rres.error) {
|
|
489
493
|
return -2;
|
|
490
494
|
}
|
|
491
495
|
if (rres.headers) {
|
|
492
|
-
filterProxyHeaders(rres.headers, res);
|
|
496
|
+
filterProxyHeaders(rres.headers, res, opt.filter);
|
|
493
497
|
}
|
|
494
498
|
res.writeHead(rres.headers?.['http-code'] ?? 200);
|
|
495
499
|
await new Promise((resolve) => {
|
|
@@ -539,14 +543,14 @@ export async function rproxy(ctr, route, opt = {}) {
|
|
|
539
543
|
const lpath = path.slice(key.length);
|
|
540
544
|
opt.method = req.method ?? 'GET';
|
|
541
545
|
opt.headers ??= {};
|
|
542
|
-
Object.assign(
|
|
546
|
+
Object.assign(filterProxyHeaders(req.headers, undefined, opt.filter), opt.headers);
|
|
543
547
|
// --- 发起请求 ---
|
|
544
548
|
const rres = await request(route[key] + lpath, req, opt);
|
|
545
549
|
if (rres.error) {
|
|
546
550
|
return false;
|
|
547
551
|
}
|
|
548
552
|
if (rres.headers) {
|
|
549
|
-
filterProxyHeaders(rres.headers, res);
|
|
553
|
+
filterProxyHeaders(rres.headers, res, opt.filter);
|
|
550
554
|
}
|
|
551
555
|
res.writeHead(rres.headers?.['http-code'] ?? 200);
|
|
552
556
|
await new Promise((resolve) => {
|
package/lib/ws.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ export interface IMproxyOptions {
|
|
|
49
49
|
'hosts'?: Record<string, string>;
|
|
50
50
|
'local'?: string;
|
|
51
51
|
'headers'?: lNet.THttpHeaders;
|
|
52
|
+
/** --- 过滤 header,返回 true 则留下 --- */
|
|
53
|
+
filter?: (h: string) => boolean;
|
|
52
54
|
/** --- 小帧模式,默认 false --- */
|
|
53
55
|
'mode'?: EFrameReceiveMode;
|
|
54
56
|
/** --- 加密模式,默认 true --- */
|
|
@@ -61,6 +63,8 @@ export interface IRproxyOptions {
|
|
|
61
63
|
'hosts'?: Record<string, string>;
|
|
62
64
|
'local'?: string;
|
|
63
65
|
'headers'?: lNet.THttpHeaders;
|
|
66
|
+
/** --- 过滤 header,返回 true 则留下 --- */
|
|
67
|
+
filter?: (h: string) => boolean;
|
|
64
68
|
/** --- 小帧模式,默认 false --- */
|
|
65
69
|
'mode'?: EFrameReceiveMode;
|
|
66
70
|
/** --- 加密模式,默认 true --- */
|
package/lib/ws.js
CHANGED
|
@@ -283,6 +283,10 @@ function bindPipe(s1, s2) {
|
|
|
283
283
|
switch (msg.opcode) {
|
|
284
284
|
case EOpcode.TEXT:
|
|
285
285
|
case EOpcode.BINARY: {
|
|
286
|
+
if (typeof msg.data === 'string') {
|
|
287
|
+
s2.writeText(msg.data);
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
286
290
|
s2.writeBinary(msg.buffer);
|
|
287
291
|
break;
|
|
288
292
|
}
|
|
@@ -312,6 +316,10 @@ function bindPipe(s1, s2) {
|
|
|
312
316
|
switch (msg.opcode) {
|
|
313
317
|
case EOpcode.TEXT:
|
|
314
318
|
case EOpcode.BINARY: {
|
|
319
|
+
if (typeof msg.data === 'string') {
|
|
320
|
+
s1.writeText(msg.data);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
315
323
|
s1.writeBinary(msg.buffer);
|
|
316
324
|
break;
|
|
317
325
|
}
|
|
@@ -358,7 +366,7 @@ export async function mproxy(ctr, auth, opt = {}) {
|
|
|
358
366
|
return -1;
|
|
359
367
|
}
|
|
360
368
|
opt.headers ??= {};
|
|
361
|
-
Object.assign(
|
|
369
|
+
Object.assign(lNet.filterProxyHeaders(req.headers, undefined, opt.filter), opt.headers);
|
|
362
370
|
// --- 发起请求 ---
|
|
363
371
|
/** --- 远程端的双向 socket --- */
|
|
364
372
|
const rsocket = await connect(get['url'], opt);
|
|
@@ -379,7 +387,7 @@ export async function rproxy(ctr, url, opt = {}) {
|
|
|
379
387
|
/** --- 请求端产生的双向 socket --- */
|
|
380
388
|
const socket = ctr.getPrototype('_socket');
|
|
381
389
|
opt.headers ??= {};
|
|
382
|
-
Object.assign(
|
|
390
|
+
Object.assign(lNet.filterProxyHeaders(req.headers, undefined, opt.filter), opt.headers);
|
|
383
391
|
// --- 发起请求 ---
|
|
384
392
|
/** --- 远程端的双向 socket --- */
|
|
385
393
|
const rsocket = await connect(url, opt);
|
package/package.json
CHANGED
package/sys/child.js
CHANGED
|
@@ -8,7 +8,7 @@ import * as tls from 'tls';
|
|
|
8
8
|
import * as http from 'http';
|
|
9
9
|
import * as crypto from 'crypto';
|
|
10
10
|
// --- 库 ---
|
|
11
|
-
import * as
|
|
11
|
+
import * as lFs from '#kebab/lib/fs.js';
|
|
12
12
|
import * as lCore from '#kebab/lib/core.js';
|
|
13
13
|
import * as lText from '#kebab/lib/text.js';
|
|
14
14
|
import * as sCtr from '#kebab/sys/ctr.js';
|
|
@@ -214,7 +214,7 @@ async function requestHandler(req, res, https) {
|
|
|
214
214
|
}
|
|
215
215
|
const uri = lText.parseUrl(`http${https ? 's' : ''}://${host}${req.url ?? ''}`);
|
|
216
216
|
/** --- 当前的 vhost 配置文件 --- */
|
|
217
|
-
const vhost = getVhostByHostname(uri.hostname ?? '');
|
|
217
|
+
const vhost = await getVhostByHostname(uri.hostname ?? '');
|
|
218
218
|
if (!vhost) {
|
|
219
219
|
req.socket.destroy();
|
|
220
220
|
return;
|
|
@@ -227,12 +227,6 @@ async function requestHandler(req, res, https) {
|
|
|
227
227
|
return;
|
|
228
228
|
*/
|
|
229
229
|
}
|
|
230
|
-
const vhostRoot = vhost.root.replace(/\${example}/g, kebab.ROOT_PATH + 'www/example/');
|
|
231
|
-
/** --- 网站绝对根目录,末尾带 / --- */
|
|
232
|
-
let rootPath = lText.isRealPath(vhostRoot) ? vhostRoot : kebab.WWW_CWD + vhostRoot;
|
|
233
|
-
if (!rootPath.endsWith('/')) {
|
|
234
|
-
rootPath += '/';
|
|
235
|
-
}
|
|
236
230
|
/** --- 请求的路径部分,前导带 / 末尾不一定,用户怎么请求就是什么 --- */
|
|
237
231
|
let path = uri.pathname ?? '/';
|
|
238
232
|
if (path !== '/') {
|
|
@@ -248,7 +242,7 @@ async function requestHandler(req, res, https) {
|
|
|
248
242
|
if (item !== '') {
|
|
249
243
|
// --- 判断 item 是文件还是文件夹 ---
|
|
250
244
|
/** --- 'abc' / 'def.json' --- */
|
|
251
|
-
let stat = await
|
|
245
|
+
let stat = await lFs.stats(vhost.real + now + item);
|
|
252
246
|
if (!stat) {
|
|
253
247
|
res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
254
248
|
res.setHeader('content-length', 22);
|
|
@@ -259,7 +253,7 @@ async function requestHandler(req, res, https) {
|
|
|
259
253
|
if (stat.isDirectory()) {
|
|
260
254
|
now += item + '/';
|
|
261
255
|
// --- 判断是不是动态层 ---
|
|
262
|
-
stat = await
|
|
256
|
+
stat = await lFs.stats(vhost.real + now + 'kebab.json');
|
|
263
257
|
if (stat) {
|
|
264
258
|
// --- 动态层,交给 Route 处理器 ---
|
|
265
259
|
try {
|
|
@@ -267,7 +261,7 @@ async function requestHandler(req, res, https) {
|
|
|
267
261
|
'req': req,
|
|
268
262
|
'res': res,
|
|
269
263
|
'uri': uri,
|
|
270
|
-
'rootPath':
|
|
264
|
+
'rootPath': vhost.real + now,
|
|
271
265
|
'urlBase': '/' + now,
|
|
272
266
|
'path': path.slice(('/' + pathList.slice(0, i).join('/')).length + 1),
|
|
273
267
|
'timer': timer
|
|
@@ -295,7 +289,7 @@ async function requestHandler(req, res, https) {
|
|
|
295
289
|
}
|
|
296
290
|
else {
|
|
297
291
|
// --- 文件,直接输出并结束 ---
|
|
298
|
-
await
|
|
292
|
+
await lFs.readToResponse(vhost.real + now + item, req, res, stat);
|
|
299
293
|
return;
|
|
300
294
|
}
|
|
301
295
|
}
|
|
@@ -305,7 +299,7 @@ async function requestHandler(req, res, https) {
|
|
|
305
299
|
break;
|
|
306
300
|
}
|
|
307
301
|
// --- 本层是根,判断根是不是动态层 ---
|
|
308
|
-
const stat = await
|
|
302
|
+
const stat = await lFs.stats(vhost.real + now + 'kebab.json');
|
|
309
303
|
if (stat) {
|
|
310
304
|
// --- 动态层,交给 Route 处理器 ---
|
|
311
305
|
try {
|
|
@@ -313,7 +307,7 @@ async function requestHandler(req, res, https) {
|
|
|
313
307
|
'req': req,
|
|
314
308
|
'res': res,
|
|
315
309
|
'uri': uri,
|
|
316
|
-
'rootPath':
|
|
310
|
+
'rootPath': vhost.real + now,
|
|
317
311
|
'urlBase': '/' + now,
|
|
318
312
|
'path': path.slice(1),
|
|
319
313
|
'timer': timer
|
|
@@ -335,9 +329,9 @@ async function requestHandler(req, res, https) {
|
|
|
335
329
|
// --- 最后一层是目录,且不是动态层,判断有没有主页,有则输出,没有则 403 出错 ---
|
|
336
330
|
const indexFiles = ['index.html', 'index.htm'];
|
|
337
331
|
for (const indexFile of indexFiles) {
|
|
338
|
-
const stat = await
|
|
332
|
+
const stat = await lFs.isFile(vhost.real + now + indexFile);
|
|
339
333
|
if (stat) {
|
|
340
|
-
await
|
|
334
|
+
await lFs.readToResponse(vhost.real + now + indexFile, req, res, stat);
|
|
341
335
|
return;
|
|
342
336
|
}
|
|
343
337
|
}
|
|
@@ -357,17 +351,11 @@ async function upgradeHandler(req, socket, https) {
|
|
|
357
351
|
// --- 当前 uri ---
|
|
358
352
|
const uri = lText.parseUrl(`ws${https ? 's' : ''}://${req.headers['host'] ?? ''}${req.url ?? ''}`);
|
|
359
353
|
/** --- 当前的 vhost 配置文件 --- */
|
|
360
|
-
const vhost = getVhostByHostname(uri.hostname ?? '');
|
|
354
|
+
const vhost = await getVhostByHostname(uri.hostname ?? '');
|
|
361
355
|
if (!vhost) {
|
|
362
356
|
socket.destroy();
|
|
363
357
|
return;
|
|
364
358
|
}
|
|
365
|
-
const vhostRoot = vhost.root.replace(/\${example}/g, kebab.ROOT_PATH + 'www/example/');
|
|
366
|
-
/** --- 网站绝对根目录,末尾带 / --- */
|
|
367
|
-
let rootPath = lText.isRealPath(vhostRoot) ? vhostRoot : kebab.WWW_CWD + vhostRoot;
|
|
368
|
-
if (!rootPath.endsWith('/')) {
|
|
369
|
-
rootPath += '/';
|
|
370
|
-
}
|
|
371
359
|
/** --- 请求的路径部分,前导带 / 末尾不一定,用户怎么请求就是什么 --- */
|
|
372
360
|
let path = uri.pathname ?? '/';
|
|
373
361
|
if (path !== '/') {
|
|
@@ -383,7 +371,7 @@ async function upgradeHandler(req, socket, https) {
|
|
|
383
371
|
if (item !== '') {
|
|
384
372
|
// --- 判断 item 是文件还是文件夹 ---
|
|
385
373
|
/** --- 'abc' / 'def.json' --- */
|
|
386
|
-
let stat = await
|
|
374
|
+
let stat = await lFs.stats(vhost.real + now + item);
|
|
387
375
|
if (!stat) {
|
|
388
376
|
socket.destroy();
|
|
389
377
|
return;
|
|
@@ -391,14 +379,14 @@ async function upgradeHandler(req, socket, https) {
|
|
|
391
379
|
if (stat.isDirectory()) {
|
|
392
380
|
now += item + '/';
|
|
393
381
|
// --- 判断是不是动态层 ---
|
|
394
|
-
stat = await
|
|
382
|
+
stat = await lFs.stats(vhost.real + now + 'kebab.json');
|
|
395
383
|
if (stat) {
|
|
396
384
|
// --- 动态层,交给 Route 处理器 ---
|
|
397
385
|
if (await sRoute.run({
|
|
398
386
|
'req': req,
|
|
399
387
|
'socket': socket,
|
|
400
388
|
'uri': uri,
|
|
401
|
-
'rootPath':
|
|
389
|
+
'rootPath': vhost.real + now,
|
|
402
390
|
'urlBase': '/' + now,
|
|
403
391
|
'path': path.slice(('/' + pathList.slice(0, i).join('/')).length + 1)
|
|
404
392
|
})) {
|
|
@@ -418,14 +406,14 @@ async function upgradeHandler(req, socket, https) {
|
|
|
418
406
|
break;
|
|
419
407
|
}
|
|
420
408
|
// --- 判断根是不是动态层 ---
|
|
421
|
-
const stat = await
|
|
409
|
+
const stat = await lFs.stats(vhost.real + now + 'kebab.json');
|
|
422
410
|
if (stat) {
|
|
423
411
|
// --- 动态层,交给 Route 处理器 ---
|
|
424
412
|
if (await sRoute.run({
|
|
425
413
|
'req': req,
|
|
426
414
|
'socket': socket,
|
|
427
415
|
'uri': uri,
|
|
428
|
-
'rootPath':
|
|
416
|
+
'rootPath': vhost.real + now,
|
|
429
417
|
'urlBase': '/' + now,
|
|
430
418
|
'path': path.slice(1)
|
|
431
419
|
})) {
|
|
@@ -442,7 +430,7 @@ async function upgradeHandler(req, socket, https) {
|
|
|
442
430
|
*/
|
|
443
431
|
async function reload() {
|
|
444
432
|
// --- 清除全局 config,并重新加载全局信息 ---
|
|
445
|
-
const configContent = await
|
|
433
|
+
const configContent = await lFs.getContent(kebab.CONF_CWD + 'config.json', 'utf8');
|
|
446
434
|
if (!configContent) {
|
|
447
435
|
throw `File '${kebab.CONF_CWD}config.json' not found.`;
|
|
448
436
|
}
|
|
@@ -454,13 +442,13 @@ async function reload() {
|
|
|
454
442
|
lCore.globalConfig[key] = config[key];
|
|
455
443
|
}
|
|
456
444
|
// --- 重新加载 VHOST 信息(/conf/vhost/) ---
|
|
457
|
-
const files = await
|
|
445
|
+
const files = await lFs.readDir(kebab.VHOST_CWD);
|
|
458
446
|
vhosts = [];
|
|
459
447
|
for (const file of files) {
|
|
460
448
|
if (!file.name.endsWith('.json')) {
|
|
461
449
|
continue;
|
|
462
450
|
}
|
|
463
|
-
const fstr = await
|
|
451
|
+
const fstr = await lFs.getContent(kebab.VHOST_CWD + file.name, 'utf8');
|
|
464
452
|
if (!fstr) {
|
|
465
453
|
continue;
|
|
466
454
|
}
|
|
@@ -485,12 +473,12 @@ async function reloadCert() {
|
|
|
485
473
|
certLastLoad = Date.now();
|
|
486
474
|
const cl = [];
|
|
487
475
|
try {
|
|
488
|
-
const certConfig = await
|
|
476
|
+
const certConfig = await lFs.getContent(kebab.CONF_CWD + 'cert.json', 'utf8');
|
|
489
477
|
if (certConfig) {
|
|
490
478
|
const certs = lText.parseJson(certConfig);
|
|
491
479
|
for (const item of certs) {
|
|
492
|
-
const key = await
|
|
493
|
-
const cert = await
|
|
480
|
+
const key = await lFs.getContent(lText.isRealPath(item.key) ? item.key : kebab.CERT_CWD + item.key, 'utf8');
|
|
481
|
+
const cert = await lFs.getContent(lText.isRealPath(item.cert) ? item.cert : kebab.CERT_CWD + item.cert, 'utf8');
|
|
494
482
|
if (!cert || !key) {
|
|
495
483
|
continue;
|
|
496
484
|
}
|
|
@@ -571,37 +559,62 @@ process.on('message', function (msg) {
|
|
|
571
559
|
lCore.log({}, '[CHILD][process][message] ' + lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
572
560
|
});
|
|
573
561
|
});
|
|
562
|
+
/**
|
|
563
|
+
* --- 获取 vhost 的真实路径 ---
|
|
564
|
+
* --- 替换 ${example} 为实际路径 ---
|
|
565
|
+
* --- 如果不是真实路径,添加 WWW_CWD 前缀 ---
|
|
566
|
+
* --- 确保路径以 / 结尾 ---
|
|
567
|
+
*/
|
|
568
|
+
function getVhostReal(root) {
|
|
569
|
+
let real = root.replace(/\${example}/g, kebab.ROOT_PATH + 'www/example/');
|
|
570
|
+
real = lText.isRealPath(real) ? real : kebab.WWW_CWD + real;
|
|
571
|
+
return real.endsWith('/') ? real : real + '/';
|
|
572
|
+
}
|
|
574
573
|
/**
|
|
575
574
|
* --- 获取匹配的 vhost 对象 ---
|
|
576
575
|
* --- 如果有精准匹配,以精准匹配为准,否则为通配符匹配(vSub),最后全局泛匹配(vGlobal) ---
|
|
577
576
|
* @param hostname 当前的 hostname,不带端口
|
|
578
577
|
*/
|
|
579
|
-
function getVhostByHostname(hostname) {
|
|
580
|
-
let vGlobal
|
|
578
|
+
async function getVhostByHostname(hostname) {
|
|
579
|
+
let vGlobal;
|
|
580
|
+
let vGlobalReal = '';
|
|
581
|
+
let vSub;
|
|
582
|
+
let vSubReal = '';
|
|
581
583
|
for (const vhost of vhosts) {
|
|
582
584
|
for (let domain of vhost.domains) {
|
|
583
585
|
if (domain === '*') {
|
|
584
586
|
// --- 全局泛匹配 ---
|
|
585
|
-
|
|
587
|
+
const real = getVhostReal(vhost.root);
|
|
588
|
+
if (await lFs.isDir(real)) {
|
|
589
|
+
vGlobal = vhost;
|
|
590
|
+
vGlobalReal = real;
|
|
591
|
+
}
|
|
586
592
|
}
|
|
587
593
|
else if (domain.includes('*')) {
|
|
588
594
|
// --- 通配符匹配 ---
|
|
589
595
|
domain = domain.replace(/\./g, '\\.').replace(/\*/g, '[\\w-]+?');
|
|
590
596
|
if (new RegExp(`^${domain}$`).test(hostname)) {
|
|
591
|
-
|
|
597
|
+
const real = getVhostReal(vhost.root);
|
|
598
|
+
if (await lFs.isDir(real)) {
|
|
599
|
+
vSub = vhost;
|
|
600
|
+
vSubReal = real;
|
|
601
|
+
}
|
|
592
602
|
}
|
|
593
603
|
}
|
|
594
604
|
else if (domain === hostname) {
|
|
595
605
|
// --- 完全匹配 ---
|
|
596
|
-
|
|
606
|
+
const real = getVhostReal(vhost.root);
|
|
607
|
+
if (await lFs.isDir(real)) {
|
|
608
|
+
return { ...vhost, real };
|
|
609
|
+
}
|
|
597
610
|
}
|
|
598
611
|
}
|
|
599
612
|
}
|
|
600
613
|
if (vSub) {
|
|
601
|
-
return vSub;
|
|
614
|
+
return { ...vSub, 'real': vSubReal };
|
|
602
615
|
}
|
|
603
616
|
if (vGlobal) {
|
|
604
|
-
return vGlobal;
|
|
617
|
+
return { ...vGlobal, 'real': vGlobalReal };
|
|
605
618
|
}
|
|
606
619
|
return null;
|
|
607
620
|
}
|
package/sys/ctr.d.ts
CHANGED
|
@@ -115,11 +115,11 @@ export declare class Ctr {
|
|
|
115
115
|
*/
|
|
116
116
|
onData(data: Buffer | string, opcode: lWs.EOpcode): kebab.Json;
|
|
117
117
|
/**
|
|
118
|
-
* --- 包含所有 opcode 的消息,若要发送数据需自行调用 write
|
|
118
|
+
* --- 包含所有 opcode 的消息,若要发送数据需自行调用 write 方法,data 恒定为原始 buffer,返回 false 则不会执行默认方法 ---
|
|
119
119
|
* @param data 数据
|
|
120
120
|
* @param opcode opcode
|
|
121
121
|
*/
|
|
122
|
-
onMessage(data: Buffer
|
|
122
|
+
onMessage(data: Buffer, opcode: lWs.EOpcode): undefined | boolean | Promise<undefined | boolean>;
|
|
123
123
|
/**
|
|
124
124
|
* --- WebSocket 下连接恢复可写入状态后会调用此事件,可重写此方法 ---
|
|
125
125
|
*/
|
package/sys/route.js
CHANGED
|
@@ -274,7 +274,7 @@ export async function run(data) {
|
|
|
274
274
|
wsSocket.on('message', async function (msg) {
|
|
275
275
|
switch (msg.opcode) {
|
|
276
276
|
case ws.EOpcode.CLOSE: {
|
|
277
|
-
const r = await cctr['onMessage'](msg.
|
|
277
|
+
const r = await cctr['onMessage'](msg.buffer, msg.opcode);
|
|
278
278
|
if (r === false) {
|
|
279
279
|
break;
|
|
280
280
|
}
|
|
@@ -282,7 +282,7 @@ export async function run(data) {
|
|
|
282
282
|
break;
|
|
283
283
|
}
|
|
284
284
|
case ws.EOpcode.PING: {
|
|
285
|
-
const r = await cctr['onMessage'](msg.
|
|
285
|
+
const r = await cctr['onMessage'](msg.buffer, msg.opcode);
|
|
286
286
|
if (r === false) {
|
|
287
287
|
break;
|
|
288
288
|
}
|
|
@@ -292,7 +292,7 @@ export async function run(data) {
|
|
|
292
292
|
case ws.EOpcode.BINARY:
|
|
293
293
|
case ws.EOpcode.TEXT: {
|
|
294
294
|
try {
|
|
295
|
-
const r = await cctr['onMessage'](msg.
|
|
295
|
+
const r = await cctr['onMessage'](msg.buffer, msg.opcode);
|
|
296
296
|
if (r === false) {
|
|
297
297
|
break;
|
|
298
298
|
}
|