@mzzsfy/dsh-tunnel 0.1.3 → 0.1.4
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/package.json +1 -1
- package/src/index.js +19 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mzzsfy/dsh-tunnel",
|
|
3
3
|
"description": "路径穿透隧道:在 dsh 宿主进程内把 /p/<name> 反向代理到本地 TCP 端口(HTTP strip 转发 + 声明式 WS upgrade + 3xx Location 单头改写),支持 <name>.* 子域名全路径透传(任意 WS 路径);GUI 看板手动管理隧道,设置页独立配置节与侧边栏注入开关;向 ai 注册 tunnel_open/tunnel_list/tunnel_close 工具且「允许 ai 使用」可开关(关闭即注销);代理逻辑全在插件进程内,不引入 nginx/caddy 等外部反代",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
package/src/index.js
CHANGED
|
@@ -90,10 +90,12 @@ export const SETTINGS_SCHEMA = z.object({
|
|
|
90
90
|
|
|
91
91
|
const normalizeWsPath = (value) => value.replace(/\/+$/, '')
|
|
92
92
|
|
|
93
|
-
// 校验作用于归一前的原始值; '/'
|
|
93
|
+
// 校验作用于归一前的原始值; '/' 为合法输入。空串 = 根路径归一产物(F26:
|
|
94
|
+
// '/' 去尾斜杠得 '',恢复校验须接受,否则根 WS 隧道重启丢)
|
|
94
95
|
function normalizeWsPaths(raw) {
|
|
95
96
|
if (raw === undefined) return []
|
|
96
|
-
|
|
97
|
+
const legal = (item) => typeof item === 'string' && (item === '' || WS_PATH_CHARS_RE.test(item))
|
|
98
|
+
if (!Array.isArray(raw) || raw.some((item) => !legal(item))) return undefined
|
|
97
99
|
return [...new Set(raw.map(normalizeWsPath))]
|
|
98
100
|
}
|
|
99
101
|
|
|
@@ -201,6 +203,11 @@ function forwardHttp(req, res, record, connectTimeoutMs) {
|
|
|
201
203
|
}
|
|
202
204
|
res.writeHead(proxyRes.statusCode, headers)
|
|
203
205
|
proxyRes.pipe(res)
|
|
206
|
+
// 上游响应中断即终止下游(F25,与 res close 反向联动成对):
|
|
207
|
+
// aborted 覆盖请求体阶段中断,error 覆盖响应期套接字错误;
|
|
208
|
+
// 两态都是"响应不再完整",挂着的下游连接应立刻回收
|
|
209
|
+
proxyRes.on('aborted', () => res.destroy())
|
|
210
|
+
proxyRes.on('error', () => res.destroy())
|
|
204
211
|
})
|
|
205
212
|
proxyReq.on('error', (error) => {
|
|
206
213
|
if (res.headersSent) return res.destroy()
|
|
@@ -385,6 +392,11 @@ export function apply(ctx, config) {
|
|
|
385
392
|
if (!VALID_ENTRIES.has(entry)) {
|
|
386
393
|
return { ok: false, error: `entry 不合法: 须为 ${ENTRY_PATH} 或 ${ENTRY_SUBDOMAIN}` }
|
|
387
394
|
}
|
|
395
|
+
// 自代理拒绝(F27):target 指向本监听端口时,子域名全路径透传+Host 原样
|
|
396
|
+
// 会把上游请求再导回自身,形成无限自代理环
|
|
397
|
+
if (args.targetPort === webServer.port) {
|
|
398
|
+
return { ok: false, error: `targetPort 不得为宿主监听端口 ${webServer.port}(自代理环)` }
|
|
399
|
+
}
|
|
388
400
|
// 子域名全路径全协议透传, wsPaths 无意义
|
|
389
401
|
const wsPaths = entry === ENTRY_SUBDOMAIN ? [] : normalizeWsPaths(args.wsPaths)
|
|
390
402
|
if (wsPaths === undefined) {
|
|
@@ -521,6 +533,11 @@ export function apply(ctx, config) {
|
|
|
521
533
|
console.warn(`${WARN_TAG}隧道表存在非法行, 已跳过: ${JSON.stringify(row)}`)
|
|
522
534
|
continue
|
|
523
535
|
}
|
|
536
|
+
// 自代理拒绝同 open(F27):恢复面不放行指向宿主监听端口的环
|
|
537
|
+
if (row.targetPort === webServer.port) {
|
|
538
|
+
console.warn(`${WARN_TAG}隧道 ${row.name} 的 targetPort 为宿主监听端口 ${webServer.port}(自代理环), 已跳过`)
|
|
539
|
+
continue
|
|
540
|
+
}
|
|
524
541
|
if (tunnels.has(row.name)) {
|
|
525
542
|
console.warn(`${WARN_TAG}隧道表存在重复名 ${row.name}, 仅恢复首行`)
|
|
526
543
|
continue
|