refactor: HTTP checker 质量加固
- failure actual 截断格式改为 …(共 N 字符),标量不序列化直接返回 - 新增 redos.ts 实现 ReDoS 静态检测(嵌套量词/重叠交替),启动期拒绝危险正则 - JSON body rules 共享同一次 JSON.parse 结果,避免重复解析 - checkCssRule 重构为线性流程,消除 exist:true 与无 operator 的冗余分支 - extract checkEarlyTimeout 辅助函数,明确提前 duration 检查意图 - 补充 303/307/308 重定向、相对路径 Location、混合 body rules 集成测试
This commit is contained in:
@@ -130,6 +130,28 @@ describe("checkBodyExpect (BodyRule[])", () => {
|
||||
expect(r.failure).toBeNull();
|
||||
});
|
||||
|
||||
test("多条 json 规则共享解析结果且全部通过", () => {
|
||||
const body = JSON.stringify({ count: 5, status: "healthy" });
|
||||
const originalParse = JSON.parse;
|
||||
let parseCount = 0;
|
||||
JSON.parse = ((text, reviver) => {
|
||||
parseCount++;
|
||||
return originalParse(text, reviver) as unknown;
|
||||
}) as typeof JSON.parse;
|
||||
|
||||
try {
|
||||
const r = checkBodyExpect(body, [
|
||||
{ json: { equals: "healthy", path: "$.status" } },
|
||||
{ json: { gte: 1, path: "$.count" } },
|
||||
]);
|
||||
expect(r.matched).toBe(true);
|
||||
expect(r.failure).toBeNull();
|
||||
expect(parseCount).toBe(1);
|
||||
} finally {
|
||||
JSON.parse = originalParse;
|
||||
}
|
||||
});
|
||||
|
||||
test("第二条规则失败返回正确索引", () => {
|
||||
const body = JSON.stringify({ status: "ok" });
|
||||
const r = checkBodyExpect(body, [{ contains: "ok" }, { json: { equals: "error", path: "$.status" } }]);
|
||||
|
||||
@@ -12,18 +12,18 @@ describe("truncateActual", () => {
|
||||
expect(truncateActual(str)).toBe(str);
|
||||
});
|
||||
|
||||
test("超过限制长度截断并加省略号", () => {
|
||||
test("超过限制长度截断并加省略号与字符计数", () => {
|
||||
const str = "a".repeat(300);
|
||||
const result = truncateActual(str) as string;
|
||||
expect(result.length).toBe(203);
|
||||
expect(result.endsWith("...")).toBe(true);
|
||||
expect(result).toBe(`${"a".repeat(200)}…(共 300 字符)`);
|
||||
expect(result.includes("...")).toBe(false);
|
||||
expect(result.startsWith("a".repeat(200))).toBe(true);
|
||||
});
|
||||
|
||||
test("自定义最大长度", () => {
|
||||
const str = "abcdefghij";
|
||||
const result = truncateActual(str, 5) as string;
|
||||
expect(result).toBe("abcde...");
|
||||
expect(result).toBe("abcde…(共 10 字符)");
|
||||
});
|
||||
|
||||
test("null 不截断", () => {
|
||||
@@ -34,9 +34,16 @@ describe("truncateActual", () => {
|
||||
expect(truncateActual(undefined)).toBe(undefined);
|
||||
});
|
||||
|
||||
test("数字转换为字符串后判断", () => {
|
||||
test("标量不截断", () => {
|
||||
expect(truncateActual(42)).toBe(42);
|
||||
expect(truncateActual(123456789, 3) as string).toBe("123...");
|
||||
expect(truncateActual(123456789, 3)).toBe(123456789);
|
||||
expect(truncateActual(true, 3)).toBe(true);
|
||||
});
|
||||
|
||||
test("对象序列化后超限时截断", () => {
|
||||
const result = truncateActual({ value: "x".repeat(20) }, 10) as string;
|
||||
expect(result.startsWith('{"value":"')).toBe(true);
|
||||
expect(result.endsWith("…(共 32 字符)")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,8 +63,7 @@ describe("mismatchFailure", () => {
|
||||
test("自动截断过长的 actual", () => {
|
||||
const longStr = "x".repeat(300);
|
||||
const f = mismatchFailure("body", "body[0]", "short", longStr, "too long");
|
||||
expect((f.actual as string).endsWith("...")).toBe(true);
|
||||
expect((f.actual as string).length).toBe(203);
|
||||
expect(f.actual).toBe(`${"x".repeat(200)}…(共 300 字符)`);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
25
tests/server/checker/runner/shared/redos.test.ts
Normal file
25
tests/server/checker/runner/shared/redos.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import { isUnsafeRegex } from "../../../../../src/server/checker/expect/redos";
|
||||
|
||||
describe("isUnsafeRegex", () => {
|
||||
test("识别嵌套量词", () => {
|
||||
expect(isUnsafeRegex("(a+)+$")).toBe(true);
|
||||
expect(isUnsafeRegex("(a*)*")).toBe(true);
|
||||
expect(isUnsafeRegex("(a?)+")).toBe(true);
|
||||
expect(isUnsafeRegex("(\\d+)*x")).toBe(true);
|
||||
expect(isUnsafeRegex("(?:a+)+")).toBe(true);
|
||||
});
|
||||
|
||||
test("识别重叠交替分支", () => {
|
||||
expect(isUnsafeRegex("(a|a)+")).toBe(true);
|
||||
expect(isUnsafeRegex("(a|aa)*")).toBe(true);
|
||||
});
|
||||
|
||||
test("安全正则不误判", () => {
|
||||
expect(isUnsafeRegex("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")).toBe(false);
|
||||
expect(isUnsafeRegex("^(ok|healthy)$")).toBe(false);
|
||||
expect(isUnsafeRegex("^[a-z0-9_-]+$")).toBe(false);
|
||||
expect(isUnsafeRegex("([a+])+")).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user