Skip to content

fix: RPC 推送不再下发非法保存路径,文件名按规则清洗 - #57

Merged
Wjavan merged 20 commits into
mainfrom
fix/rpc-dir-filename
Nov 11, 2026
Merged

Wjavan merged 20 commits into
mainfrom
fix/rpc-dir-filename

Conversation

@Wjavan

@Wjavan Wjavan commented Nov 10, 2026 •

Copy link
Copy Markdown
Owner

问题

推送到 Aria2 / Motrix 报「错误 16」(aria2 FILE_CREATE_ERROR,无法创建目标文件),面板却可能显示推送成功。#51

原因是三处:

  1. 保存路径默认 C:。C: 不是目录,aria2 的 applyDir 把它拼成 C:/文件名,等于往 C 盘根目录写;普通用户对根目录没有写权限,CreateFileW 返回 Access Denied,任务在 addUri 返回 GID 之后才失败,所以面板看不到。
  2. 保存路径留空仍然下发 dir: ""。aria2 把空串拼成 ./文件名,落到 aria2 进程的工作目录,而不是下载器设置里的下载目录。
  3. 文件名没按 Windows 规则清洗。safeRpcFilename 只去掉控制字符与 / \,* ? " < > | 全部放行 —— 实测直接 16;: 更隐蔽,落成 0 字节文件加一条 NTFS 数据流,目录里看着像空文件。另外 .slice(0, 255) 会切掉扩展名、切断 emoji 代理对。

补一句前提:这条支线的判据是 if (res.result) return 'success',而 aria2.addUri 对注定失败的名字照样返回 GID。所以「下载器报 16」与「面板打 ✓」可以同时成立 —— 这是为什么这些输入必须在插件侧挡掉。

改动

只改主脚本,+34 / −8。

  • rpcDefaults.dir 由 'C:' 改为 ''(只对新装生效;老用户存的 C: 靠下面的读取时归一兜住)。
  • _rpcConfig() 读取时调用 rpcDir():归一(trim、整串被引号包住时剥引号、全角冒号转半角)并校验,被拒的形态不下发 dir,改用下载器默认目录,推送结束提示一次原因;提示用 warning 色,不再绿着说成功。
  • 新增 rpcDir() 承接上一条的归一与判定。被拒形态:裸盘符(C:)、驱动相对(C:Downloads)、相对路径(Downloads)、~/、file://、含不可见字符、纯分隔符(/、//)、没有共享名的半截 UNC(\\nas\)、Windows 路径里的 <>"|?*:(剥掉 \\?\ / \\.\ 前缀再判,前缀本身的那个 ? 不算)。
  • 重写 safeRpcFilename():\ / : * ? " < > | 统一换成 _;裸设备名(CON / PRN / AUX / NUL / COM1-9 / LPT1-9,含尾随点空格的形态)前面补 _;按 UTF-8 字节截到 243 并保留扩展名(扩展名按最后一个点切,非 ASCII 扩展名同样保留);空名与纯空白名返回空串,交回 aria2 按链接取名字。
  • 面板成功提示由「已推送至 Aria2,下载已开始」改为「已提交 N 个任务给 Aria2,进度请看下载器」——addUri 只保证任务进了队列,不保证建文件成功。
  • 设置页保存路径的 placeholder 同步说明「留空则使用下载器默认目录;Windows 请填完整路径」。

没有做:七家 sendLinkToRPC 仍各自持有 aria2.addUri 报文,没有抽公共入口(那版已被 c0a1c8c 撤回);没有做推送后的 tellStatus 回查;没有剥离文件名结尾的点与空格。

为什么是 243 字节

255 是文件系统上限。aria2 下载中会在同目录写控制文件 <out>.aria2,其临时名再带 __temp 后缀,合计要占掉 12 个字符,所以名字最多 243。实测(6MB 慢速源,等任务到终态,25ms 采样目录能看到瞬态文件):

名长 243 → complete,目录里最长文件名 249(243 + .aria2),控制文件在
名长 244 → complete,目录里最长 244,控制文件没生成
名长 250 → complete,控制文件没生成
名长 255 → complete,控制文件没生成
名长 256 → errorCode 16,数据不落盘

所以 244–255 这一段的表现最容易被误判:数据文件在、tellStatus 报 complete、errorCode=0,丢的是断点续传 / session 记录,不是下载本身。取 243 就是拿 12 个字符的名字换回续传能力,不能按 255 取。

按字节而不是码元:NTFS 限 255 码元,但 ext4 / APFS 的 NAME_MAX 限 255 字节。这个插件的 rpcDir 接受 /下载 这类 POSIX 路径、validRpcDomain 接受局域网地址,说明 NAS 上的 aria2 是被支持目标 —— 按码元截断时 243 个汉字 = 729 字节,在 NAS 上照样 16。代价是中文名最多 79 个汉字加扩展名(ASCII 仍是 243 字节)。

验证

RPC 层真跑(aria2 1.37.0-motrix.23,本地 HTTP 源,aria2.addUri + aria2.tellStatus,看落盘字节)

文件名组:

原名 基线 改动后
S01E01: Pilot.mp4 落成 0 字节 S01E01 + NTFS 数据流(不报错) S01E01_ Pilot.mp4,4096B
a?b*c|d<e>f"g.zip errorCode 16,无文件 a_b_c_d_e_f_g.zip,4096B
第1集:开端.mp4 原样 原样(全角冒号保留),4096B
NUL errorCode 13,无文件 _NUL,落盘
NUL. / NUL errorCode 13,无文件 _NUL. / _NUL ,落盘
CON / CON.txt / nul.mp4 正常落盘 正常落盘(CON 会被补成 _CON)
中×300 + .mp4 截成 255 字,扩展名丢失 79 个汉字 + .mp4(83 码点、241 字节)
x×300 + .mp4 截成 255 字 243 字节
a×254 + 😀.mp4 留下孤立代理对 243 字节,无孤立代理对,保留 .mp4
长×300 + .文件 扩展名整段丢失 扩展名 .文件 保留
空名 / 纯空白 写死成同名文件,同批相遇即撞名 交回 aria2 按链接取名

保存路径组:

保存路径 结果
C:(基线脚本) errorCode 16,files[0].path = C:/…,磁盘无文件
C:(本次改动) 不下发 dir,complete,落下载器默认目录
留空 不下发 dir,complete
C:Downloads / Downloads 不下发 dir,complete
/ / // 不下发 dir,complete(基线会写盘根 / errorCode 18)
C:\a?b / C:\a*b / C:\a:b 不下发 dir,complete(基线 errorCode 18)
\\nas\ / \\nas\\ / \\127.0.0.1\ 不下发 dir,complete(基线 errorCode 16)
\\?\a?b / \\?\C: / \\?\?x 不下发 dir,complete(基线 errorCode 16)
D:\Downloads 原样下发,落该子目录
"D:\...\quoted"(整串带引号) 去引号后下发
/data/'quoted'(名字里有引号) 原样下发,不被当外层引号剥掉
\\?\C:\x / \\?\D:\ / \\.\C:\x(长路径前缀) 原样放行(实测 complete)
\\?\UNC\nas\share(扩展长度 UNC) 不下发 dir,提示「这种长路径写法不受支持」
/下载、/data/movies、//nas/share 原样放行(POSIX / NAS 路径合法)

浏览器端:ego lite + 篡改猴 5.5.1,夸克网盘实机走完整面板流程,保存路径设为 C:,推送后面板提示「已提交 1 个任务给 Aria2」,文件落 D:\Downloads,C:\ 根目录无残留。

node --check 通过;本地 harness rpc_cfg_check 101/101。

保存路径只填盘符或相对路径时不下发 dir,改用下载器默认目录;留空同样不下发,
不再落进 aria2 的工作目录。文件名统一处理 Windows 非法字符、结尾点空格与设备名,
超长按码点截断并保留扩展名。七家推送收口到 _rpcAddUri,面板改说「已提交」。
收口时这一行被写成了占位符,推送会带一条无效 Cookie。
字符集归网盘管:七家上传时就拒掉 :*?"<>| 这类字符,
这边再改一遍只是白改一遍名字。留下的是网盘管不到的:
路径分隔符、长度(NTFS 按码元算 255,aria2 还要写
<out>.aria2 控制文件,留 6 个)。
addUri 对非法名也返回 GID,面板只看到 GID 就判成功,
? * " < > | 的 errorCode 16 和 : 的 0 字节落盘都看不见。
裸 NUL 会被 Windows 当设备吞掉,补前缀。
控制文件名是 <out>.aria2__temp,多 12 个字符,截断相应收到 243。
NTFS 限 255 码元、ext4/APFS 限 255 字节,按码元截断时
243 个汉字是 721 字节,RPC 指向 Linux 上的 aria2 会 error 16。
设备名只认整名,NUL. / NUL 这类形态会绕过护栏被当设备吞掉。
占位文案删掉「目录需已存在」,实测 aria2 会自建目录。
\?\ / \.\ 前缀本身含 ?,剥掉后无条件 slice(2) 会把非法字符跳过:
rpcDir('\?\a?b') 剥完是 'a?b',再 slice(2) 只剩 'b',? 消失 → 放行。
实测这三个形态在 aria2 RPC 层全是 errorCode 16,且 addUri 照返 GID、面板打勾。

改为:剥前缀后必须仍是完整路径(盘符或 UNC),判非法字符时只在盘符形态下跳过盘符。
- 半截 UNC(\nas\、\127.0.0.1\)落不了盘,实测 errorCode 16,改要求共享名
- 目录名以引号结尾是合法的 POSIX 名(/data/'quoted'),原来被当成外层引号剥掉,静默改到别的目录;改成整串被引号包住才剥
- 扩展名类放开到非分隔符,避免超长中文名/双后缀被整段丢掉
- 保存路径被拒时提示用 warning 色,不再绿着说成功
写死 download 会让一批无名文件在 --allow-overwrite=false 下互相撞名:
实测三个不同 URL 连推,out='' 三件全部 complete,out='download' 后两件 error 13。
原文案说「不是完整路径;请填完整路径」,但 \?\UNC\nas\share 这类本身就是完整路径,
只是本脚本不支持该写法,提示误导用户去改路径。
@Wjavan Wjavan changed the title fix: RPC 推送不再下发非法保存路径,文件名按 Windows 规则清洗 fix: RPC 推送不再下发非法保存路径,文件名按规则清洗 Nov 11, 2026
「请填完整路径」会把用户从 C: 引到 C:\,而盘符根照样 errorCode 16——
插件无法预判根目录写权限,所以不改判定,只改提示指向具体目录。

toast 用的 warning 类型在样式表里没有对应规则,退回无类型(基础中性样式)。
initDefaultConfig 只补缺失键,老用户存档里的 C: 不会被覆盖,每次推送都会
被 rpcDir 拒绝并提示一次。这里把脚本自己写下的那个默认值一次性清空。
@Wjavan
Wjavan merged commit 26ec787 into main Nov 11, 2026
3 checks passed
@Wjavan
Wjavan deleted the fix/rpc-dir-filename branch November 11, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant