先核來源與已訂規則
本例小型 zlib 資料,每項解後最多 5 字節、整包 10。各項聲稱 1,真正解開卻各 4。規則計實際輸出字節,不計聲明或壓縮大小;這是解後配額示範,不是防惡意解壓分配機制。
| 紀錄 | 輸入 JSON |
|---|---|
| 原例輸入 | {"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1},{"compressed":"eJxzdnZ2BgACogEN","claimedLength":1}]} |
比較兩條實際路徑
更正實量 4+4+4=12,雖每項未超 5,整包仍須停;錯聲明合計 1+1+1=3 卻收了。
| 路徑 | 輸出 JSON |
|---|---|
| 錯誤路徑 | {"accepted":true,"lengths":[1,1,1],"total":3} |
| 更正路徑 | {"accepted":false,"lengths":[4,4,4],"total":12} |
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};
import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
const lengths=i.members.map(m=>corrected?inflateSync(Buffer.from(m.compressed,'base64')).byteLength:m.claimedLength);
const total=lengths.reduce((a,b)=>a+b,0);return {accepted:lengths.every(n=>n<=i.memberLimit)&&total<=i.totalLimit,lengths,total};
};
const cases=[{"label":"misleading base","input":{"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1},{"compressed":"eJxzdnZ2BgACogEN","claimedLength":1}]},"expected":{"accepted":true,"lengths":[1,1,1],"total":3},"corrected":false},{"label":"corrected base","input":{"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1},{"compressed":"eJxzdnZ2BgACogEN","claimedLength":1}]},"expected":{"accepted":false,"lengths":[4,4,4],"total":12},"corrected":true},{"label":"two actual four-byte members","input":{"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1}]},"expected":{"accepted":true,"lengths":[4,4],"total":8},"corrected":true},{"label":"exact actual total limit","input":{"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1},{"compressed":"eJxzdgYAAMsAhw==","claimedLength":1}]},"expected":{"accepted":true,"lengths":[4,4,2],"total":10},"corrected":true}];
for(const test of cases){
const actual=run(test.input,test.corrected);
assert.deepEqual(actual,test.expected,test.label);
console.log(test.label,actual);
}
下次載入前核邊界
兩個四字節項總 8 可過;四、四、二剛好 10,也符包含上限的配額。
| 情況 | 輸入 JSON | 預期輸出 JSON |
|---|---|---|
| 實際合計八字節 | {"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1}]} | {"accepted":true,"lengths":[4,4],"total":8} |
| 實際剛好十字節上限 | {"memberLimit":5,"totalLimit":10,"members":[{"compressed":"eJxzdHR0BAACjgEF","claimedLength":1},{"compressed":"eJxzcnJyAgACmAEJ","claimedLength":1},{"compressed":"eJxzdgYAAMsAhw==","claimedLength":1}]} | {"accepted":true,"lengths":[4,4,2],"total":10} |
三項都聲稱一字節,未量可否直接收?
查看參考答案
不可,真正解開十二字節,本例十字節配額須暫停整包。