fix(panel): overview net 块括号配平(批2 DNS 并入时多写一个 },浏览器 Extra data 破页)+自校验换严格平衡检查(jv_parse 容忍尾随垃圾,浏览器不容忍)
This commit is contained in:
1 parent
524e5d6967
commit
54e737a4a2
1 file changed
+24
-3
@@ -222,6 +222,26 @@ static int utf8_seq_len(unsigned char lead)
|
||||
|
||||
/* 校验从 p 开始的 len 字节序列是否构成合法 UTF-8 字符(len 由 utf8_seq_len 给出)。
|
||||
* 调用方须保证 p+len 在可读边界内。检查续字节/overlong/代理对/超 U+10FFFF。 */
|
||||
/* 严格 JSON 平衡检查(字符串态+括号深度;要求恰好收完,防尾随垃圾/多括号)。
|
||||
* jv_parse 只解析首个完整值、容忍尾随内容——浏览器 JSON.parse 不容忍,故自校验必须用本函数。 */
|
||||
static int json_strict_balanced(const char *b, size_t n)
|
||||
{
|
||||
int depth = 0, instr = 0, esc = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char c = b[i];
|
||||
if (instr) {
|
||||
if (esc) esc = 0;
|
||||
else if (c == '\\') esc = 1;
|
||||
else if (c == '"') instr = 0;
|
||||
continue;
|
||||
}
|
||||
if (c == '"') { instr = 1; continue; }
|
||||
if (c == '{' || c == '[') depth++;
|
||||
else if (c == '}' || c == ']') { if (--depth < 0) return 0; }
|
||||
}
|
||||
return depth == 0 && !instr;
|
||||
}
|
||||
|
||||
static int utf8_seq_ok(const char *p, int len)
|
||||
{
|
||||
unsigned char c0 = (unsigned char)p[0];
|
||||
@@ -1393,7 +1413,7 @@ static int net_block_fill(sbuf_t *s)
|
||||
sA(s, ",\"net\":{");
|
||||
sA(s, "%s", njson + 1); /* 去首 { 的状态内层 */
|
||||
if (drc == 0 && dns.b) sA(s, ",\"dns\":%s", dns.b);
|
||||
sA(s, "}}");
|
||||
sA(s, "}"); /* net 块只开了一个 {,一个 } 收尾(批2 曾写 }} 多一括号,浏览器 Extra data 破页 2026-09-02) */
|
||||
sbuf_free(&dns);
|
||||
return 0;
|
||||
}
|
||||
@@ -1688,11 +1708,12 @@ static int api_overview(int sock)
|
||||
size_t slen = s.b ? strlen(s.b) : 0;
|
||||
int nul_inside = s.b && (slen != s.n); /* 内嵌 NUL:strlen < s.n */
|
||||
int utf8_bad = s.b && !utf8_valid_n(s.b, s.n);
|
||||
if (s.b && (nul_inside || utf8_bad)) { chk = NULL; }
|
||||
int unbalanced = s.b && !json_strict_balanced(s.b, s.n); /* 尾随垃圾/多括号(jv_parse 容忍,浏览器不容忍) */
|
||||
if (s.b && (nul_inside || utf8_bad || unbalanced)) { chk = NULL; }
|
||||
if (!chk && s.b) {
|
||||
FILE *df = fopen("/tmp/overview_bad.json", "w");
|
||||
if (df) { fwrite(s.b, 1, s.n, df); fclose(df); }
|
||||
panel_log("overview: SELF-CHECK fail (nul=%d utf8_bad=%d n=%zu strlen=%zu), raw dumped /tmp/overview_bad.json", nul_inside, utf8_bad, s.n, slen);
|
||||
panel_log("overview: SELF-CHECK fail (nul=%d utf8_bad=%d unbalanced=%d n=%zu strlen=%zu), raw dumped /tmp/overview_bad.json", nul_inside, utf8_bad, unbalanced, s.n, slen);
|
||||
sbuf_free(&s);
|
||||
return send_err(sock, 500, "INTERNAL", "overview 聚合输出未通过 JSON 自校验(原始数据已留 /tmp/overview_bad.json)");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user