docs(fsys): 修正 README 缓存/兼容性措辞,测试页补 video Range 用例,审计报告勘误
This commit is contained in:
1 parent
b6a1cadf25
commit
bb5e3b973f
4 files changed
+18
-2
No files matched your search
@@ -27,6 +27,7 @@ fsys 是 Python `static` 模块的 C++20 重实现(libhttp + libmsg + boost::j
|
||||
- **位置**: `load_config()` 步骤 8(原 L347-369)
|
||||
- **问题**: 相对路径 `static_root` 通过 `/proc/self/exe` 基于可执行文件目录解析。二进制位于 `fsys/build/fsys`,而 `public` 符号链接位于 `fsys/public`,因此 `./public` 解析为 `fsys/build/./public`(不存在)。更严重的是构造函数 `fs::create_directories()` 会**静默创建空目录**,服务启动正常但所有路由返回 404/500,无告警。
|
||||
- **修复**: 相对路径改为基于 `fs::current_path()` 解析(`_run.sh` 以模块目录为 cwd 启动,与 Python 版 `BASE_DIR` 语义一致;Docker 使用绝对路径 `STATIC_ROOT=/app/public`,不受影响)。SSL 证书路径同样修复。
|
||||
- **勘误(2026-08-08 后)**: 原描述中 `fsys/public` 为指向 `../static/public` 的符号链接;现已改为真实目录,内含自检测试页(`index.html` 等),不再与 static 共享内容。
|
||||
|
||||
### F-2: favicon 代理 `CURLOPT_FOLLOWLOCATION` 盲跟重定向绕过 SSRF 校验(回归) ✅ 已修复
|
||||
|
||||
@@ -191,6 +192,9 @@ macOS/Linux 双开发环境约定,Linux 编译需覆盖 `INCS/LIBS/RPATH`(
|
||||
| `POST /api/hash` | ✓ 哈希值与 Python 版逐位一致 |
|
||||
| `POST /api/check_user` | ✓ 与 Python 版行为一致(当前环境 db Users 查询失败,两版同返 500 query failed,非 fsys 缺陷) |
|
||||
| dnfs 代理 `/get_notes` | ✓ 透传(上游自身 500,直连上游同果,非代理缺陷) |
|
||||
| `/video/*` 无 Range 200 / Range 206(Content-Range/Content-Length)/ 越界 416 | ✓(2026-08-08 补测,见下) |
|
||||
|
||||
> **补充(2026-08-08)**: 初轮冒烟未覆盖 `/video/*` Range 路径(当时无测试媒体文件)。后在 `fsys/public/` 内置自检测试页(`index.html`,15 项自动检查)及 `test/sample.mp4`(1KB),补齐 Range 用例:全量 200 + `Accept-Ranges: bytes`、`bytes=0-99` → 206 + `Content-Range: bytes 0-99/1024` + `Content-Length: 100`、`bytes=999999-` → 416,均验证通过(F-4 的 416 分支同时覆盖)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
基于 libhttp + libmsg 的 C++20 静态文件托管与前端页面服务,监听 `127.0.0.1:9200`。
|
||||
|
||||
Python/Flask `static` 模块的生产级 C++ 重写,接口 100% 兼容,前端零改动。
|
||||
Python/Flask `static` 模块的生产级 C++ 重写,前端零改动兼容(改进性差异:上游状态码透传使前端 401 跳转首次生效,详见审计报告 D-1)。
|
||||
|
||||
## 架构
|
||||
|
||||
@@ -39,7 +39,7 @@ fsys :9200 (libhttp 异步多线程 + CORS)
|
||||
|------|------|
|
||||
| `POST /api/hash` | SHA-256 密码哈希(限速 20/min/IP) |
|
||||
| `POST /api/check_user` | 检查用户是否已注册(限速 10/min/IP) |
|
||||
| `GET /api/favicon?url=` | favicon SSRF 防护代理(512KB 上限,1 天缓存) |
|
||||
| `GET /api/favicon?url=` | favicon SSRF 防护代理(512KB 上限,仅浏览器侧 Cache-Control 缓存 1 天,无服务端缓存) |
|
||||
|
||||
### dnfs2 代理路由
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<tr data-t="filelist_sub"><td class="name">GET /api/filelist?path=test%2F(编码子目录)</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
<tr data-t="filelist_traverse"><td class="name">GET /api/filelist?path=..%2F..(遍历应 403)</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
<tr data-t="static_file"><td class="name">GET /test/hello.txt(静态文件)</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
<tr data-t="video_range"><td class="name">GET /video/test/sample.mp4(Range 206/416)</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
<tr data-t="download"><td class="name">GET /test/hello.txt?download=true(附件头)</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
<tr data-t="utf8_path"><td class="name">GET 中文文件名(URL 解码)</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
<tr data-t="hash"><td class="name">POST /api/hash(sha256("test123"))</td><td class="st pending">—</td><td class="detail"></td></tr>
|
||||
@@ -109,6 +110,17 @@ const tests = {
|
||||
const ok = res.status === 200 && text.includes('hello fsys');
|
||||
setRow('static_file', ok, `HTTP ${res.status}, ${(res.headers.get('content-type') || '').split(';')[0]}`);
|
||||
},
|
||||
async video_range() {
|
||||
const full = await fetch('/video/test/sample.mp4');
|
||||
const partial = await fetch('/video/test/sample.mp4', { headers: { Range: 'bytes=0-99' } });
|
||||
const bad = await fetch('/video/test/sample.mp4', { headers: { Range: 'bytes=999999-' } });
|
||||
const cr = partial.headers.get('content-range') || '';
|
||||
const ok = full.status === 200 && full.headers.get('accept-ranges') === 'bytes'
|
||||
&& partial.status === 206 && cr.startsWith('bytes 0-99/')
|
||||
&& partial.headers.get('content-length') === '100'
|
||||
&& bad.status === 416;
|
||||
setRow('video_range', ok, `full=${full.status}, range=${partial.status} ${cr}, bad=${bad.status}(期望 416)`);
|
||||
},
|
||||
async download() {
|
||||
const { res } = await j('/test/hello.txt?download=true');
|
||||
const cd = res.headers.get('content-disposition') || '';
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user