fix: symlink 探测有界并发 + UNC 标记平台中性化(回应 CR/自审)
- fs-tree: symlink 目标 stat 从串行改为 32 并发工作池(readdir 流关闭后统一 探测),symlink 密集/网络目标目录不再累加延迟;顺序与分类语义不变 - html-route: 解码不再重建反斜杠 UNC,统一重建为平台中性的 //server/share/... 前斜杠形态(win32/POSIX 均正确 resolve),从而删除 windowsPathStyle 平台信号 与 client isWindowsStylePath 助手;同时解决无 cwd 时正斜杠 UNC 的往返盲点 - 测试/文档同步;移除未使用的 isPosix
This commit is contained in:
+16
-21
@@ -13,16 +13,17 @@
|
||||
* /sidebar/html/S/Users/me/proj/index.html
|
||||
* + ./style.css → /sidebar/html/S/Users/me/proj/style.css
|
||||
* Windows: C:\Users\me\a.html → /sidebar/html/S/C%3A/Users/me/a.html
|
||||
* Windows UNC (windowsPathStyle): \\server\share\proj\a.html
|
||||
* UNC (\\server\share\... or //server/share/...):
|
||||
* → /sidebar/html/S//server/share/proj/a.html ('//' right after the
|
||||
* sessionId marks the UNC prefix; the WHATWG URL keeps '//' intact so
|
||||
* relative assets still resolve inside the same route)
|
||||
*
|
||||
* The `windowsPathStyle` flag is the platform guard: a leading `//` is a
|
||||
* legitimate POSIX absolute path, so the UNC marker is only emitted for
|
||||
* sessions whose cwd shape identifies them as Windows (see the client's
|
||||
* isWindowsStylePath) — otherwise a POSIX `//server/share/...` would decode
|
||||
* back to a backslash UNC form the host then rejects.
|
||||
* The decoder rebuilds the marker as a forward-slash `//server/share/...`
|
||||
* path. That form is intentionally platform-neutral: `node:path` resolves it
|
||||
* to `\\server\share\...` on win32 and `/server/share/...` on POSIX, so the
|
||||
* host's existing requireAbsolute + isWithin fence needs no platform signal
|
||||
* (a leading `//` is a legal POSIX absolute path, so no data is lost on
|
||||
* either platform).
|
||||
*
|
||||
* This module is intentionally dependency-free (no node imports, no wire
|
||||
* helpers) so the client bundle can import `encodeHtmlUrl` without tripping
|
||||
@@ -45,15 +46,9 @@ export type HtmlDecodeResult =
|
||||
/** The route prefix both encoders/decoders agree on. */
|
||||
export const HTML_ROUTE_PREFIX = '/sidebar/html/'
|
||||
|
||||
/**
|
||||
* Build the route URL for one absolute file path (client + tests).
|
||||
* @param windowsPathStyle - whether the path belongs to a Windows-style
|
||||
* session (drive or UNC). Only then is a `\\`/`//`-prefixed UNC path marked
|
||||
* with the '//' marker; POSIX sessions keep `//` as an ordinary absolute
|
||||
* path (see the module comment for the platform guard rationale).
|
||||
*/
|
||||
export function encodeHtmlUrl(sessionId: string, path: string, windowsPathStyle = false): string {
|
||||
const unc = windowsPathStyle && /^[\\/]{2}[^\\/]/.test(path)
|
||||
/** Build the route URL for one absolute file path (client + tests). */
|
||||
export function encodeHtmlUrl(sessionId: string, path: string): string {
|
||||
const unc = /^[\\/]{2}[^\\/]/.test(path)
|
||||
const segments = path.split(/[\\/]+/).filter(segment => segment !== '')
|
||||
return `${HTML_ROUTE_PREFIX}${encodeURIComponent(sessionId)}/${unc ? '/' : ''}${segments.map(encodeURIComponent).join('/')}`
|
||||
}
|
||||
@@ -84,9 +79,9 @@ export function decodeHtmlUrl(pathname: string): HtmlDecodeResult {
|
||||
return { ok: false, status: 400, message: 'sessionId and file path are required' }
|
||||
}
|
||||
// An empty FIRST path segment is the UNC marker (encodeHtmlUrl emits
|
||||
// '<sid>//server/share/...' for Windows UNC paths); the encoder filters
|
||||
// empty segments everywhere else, so an empty segment can only be the
|
||||
// marker or a malformed URL — both handled here.
|
||||
// '<sid>//server/share/...' for UNC paths); the encoder filters empty
|
||||
// segments everywhere else, so an empty segment can only be the marker or
|
||||
// a malformed URL — both handled here.
|
||||
const unc = pathSegments[0] === ''
|
||||
const tail = unc ? pathSegments.slice(1) : pathSegments
|
||||
if (tail.length === 0 || tail.some(segment => segment === '')) {
|
||||
@@ -94,9 +89,9 @@ export function decodeHtmlUrl(pathname: string): HtmlDecodeResult {
|
||||
}
|
||||
let path: string
|
||||
if (unc) {
|
||||
// Rebuild the UNC form \\server\share\... so requireAbsolute() +
|
||||
// isWithin(cwd) see the same path the explorer works with.
|
||||
path = `\\\\${tail.join('\\')}`
|
||||
// Rebuild the platform-neutral forward-slash form `//server/share/...`;
|
||||
// requireAbsolute() resolves it to the platform's own UNC/POSIX spelling.
|
||||
path = `//${tail.join('/')}`
|
||||
} else if (/^[A-Za-z]:$/.test(tail[0] ?? '')) {
|
||||
// A Windows drive segment ('D:') is the FIRST path segment of an encoded
|
||||
// drive path. Rejoining it with a leading slash would yield '/D:/work/...'
|
||||
|
||||
Reference in New Issue
Block a user