Files
SnowLuma/.pnpm-store/v11/files/bf/c4003bff49d95accc05b1b8ea21950906d445829d480628a3cab842d1deb258eea70dc530f7ed3f964050c3cb3482fa9c89604488d6ec1dd1d13b213872ea6
TanTan 2a69b23b47
Dev Build / cleanup (push) Canceled after 0s
Dev Build / typecheck (push) Canceled after 0s
Dev Build / build (linux-arm64, ubuntu-24.04-arm, linux-arm64) (push) Canceled after 0s
Dev Build / build (linux-x64, ubuntu-latest, linux-x64) (push) Canceled after 0s
Dev Build / build (win-x64, windows-latest, win32-x64) (push) Canceled after 0s
Dev Build / dispatch-dev-docker (push) Canceled after 0s
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

194 lines
5.0 KiB
Plaintext

//#region src/utils/accept.ts
const isWhitespace = (char) => char === 32 || char === 9 || char === 10 || char === 13;
const consumeWhitespace = (acceptHeader, startIndex) => {
while (startIndex < acceptHeader.length) {
if (!isWhitespace(acceptHeader.charCodeAt(startIndex))) break;
startIndex++;
}
return startIndex;
};
const ignoreTrailingWhitespace = (acceptHeader, startIndex) => {
while (startIndex > 0) {
if (!isWhitespace(acceptHeader.charCodeAt(startIndex - 1))) break;
startIndex--;
}
return startIndex;
};
const skipInvalidParam = (acceptHeader, startIndex) => {
while (startIndex < acceptHeader.length) {
const char = acceptHeader.charCodeAt(startIndex);
if (char === 59) return [startIndex + 1, true];
if (char === 44) return [startIndex + 1, false];
startIndex++;
}
return [startIndex, false];
};
const skipInvalidAcceptValue = (acceptHeader, startIndex) => {
let i = startIndex;
let inQuotes = false;
while (i < acceptHeader.length) {
const char = acceptHeader.charCodeAt(i);
if (inQuotes && char === 92) i++;
else if (char === 34) inQuotes = !inQuotes;
else if (!inQuotes && char === 44) return i + 1;
i++;
}
return i;
};
const getNextParam = (acceptHeader, startIndex) => {
startIndex = consumeWhitespace(acceptHeader, startIndex);
let i = startIndex;
let key;
let value;
let hasNext = false;
while (i < acceptHeader.length) {
const char = acceptHeader.charCodeAt(i);
if (char === 61) {
key = acceptHeader.slice(startIndex, ignoreTrailingWhitespace(acceptHeader, i));
i++;
break;
}
if (char === 59) return [
i + 1,
void 0,
void 0,
true
];
if (char === 44) return [
i + 1,
void 0,
void 0,
false
];
i++;
}
if (key === void 0) return [
i,
void 0,
void 0,
false
];
i = consumeWhitespace(acceptHeader, i);
if (acceptHeader.charCodeAt(i) === 61) {
const skipResult = skipInvalidParam(acceptHeader, i + 1);
return [
skipResult[0],
key,
void 0,
skipResult[1]
];
}
let inQuotes = false;
const paramStartIndex = i;
while (i < acceptHeader.length) {
const char = acceptHeader.charCodeAt(i);
if (inQuotes && char === 92) i++;
else if (char === 34) {
if (inQuotes) {
let nextIndex = consumeWhitespace(acceptHeader, i + 1);
const nextChar = acceptHeader.charCodeAt(nextIndex);
if (nextIndex < acceptHeader.length && !(nextChar === 59 || nextChar === 44)) {
const skipResult = skipInvalidParam(acceptHeader, nextIndex);
return [
skipResult[0],
key,
void 0,
skipResult[1]
];
}
value = acceptHeader.slice(paramStartIndex + 1, i);
if (value.includes("\\")) value = value.replace(/\\(.)/g, "$1");
if (nextChar === 44) return [
nextIndex + 1,
key,
value,
false
];
if (nextChar === 59) {
hasNext = true;
nextIndex++;
}
i = nextIndex;
break;
}
inQuotes = true;
} else if (!inQuotes && (char === 59 || char === 44)) {
value = acceptHeader.slice(paramStartIndex, ignoreTrailingWhitespace(acceptHeader, i));
if (char === 59) hasNext = true;
i++;
break;
}
i++;
}
return [
i,
key,
value ?? acceptHeader.slice(paramStartIndex, ignoreTrailingWhitespace(acceptHeader, i)),
hasNext
];
};
const getNextAcceptValue = (acceptHeader, startIndex) => {
const accept = {
type: "",
params: Object.create(null),
q: 1
};
startIndex = consumeWhitespace(acceptHeader, startIndex);
let i = startIndex;
while (i < acceptHeader.length) {
const char = acceptHeader.charCodeAt(i);
if (char === 59 || char === 44) {
accept.type = acceptHeader.slice(startIndex, ignoreTrailingWhitespace(acceptHeader, i));
i++;
if (char === 44) return [i, accept.type ? accept : void 0];
if (!accept.type) return [skipInvalidAcceptValue(acceptHeader, i), void 0];
break;
}
i++;
}
if (!accept.type) {
accept.type = acceptHeader.slice(startIndex, ignoreTrailingWhitespace(acceptHeader, acceptHeader.length));
return [acceptHeader.length, accept.type ? accept : void 0];
}
let param;
let value;
let hasNext;
while (i < acceptHeader.length) {
[i, param, value, hasNext] = getNextParam(acceptHeader, i);
if (param && value) accept.params[param] = value;
if (!hasNext) break;
}
return [i, accept];
};
const parseAccept = (acceptHeader) => {
if (!acceptHeader) return [];
const values = [];
let i = 0;
let accept;
let requiresSort = false;
let lastAccept;
while (i < acceptHeader.length) {
[i, accept] = getNextAcceptValue(acceptHeader, i);
if (accept) {
accept.q = parseQuality(accept.params.q ?? accept.params.Q);
values.push(accept);
if (lastAccept && lastAccept.q < accept.q) requiresSort = true;
lastAccept = accept;
}
}
if (requiresSort) values.sort((a, b) => b.q - a.q);
return values;
};
const parseQuality = (qVal) => {
if (qVal === void 0) return 1;
if (qVal === "") return 1;
if (qVal === "NaN") return 0;
const num = Number(qVal);
if (Number.isNaN(num)) return 1;
if (num < 0) return 0;
if (num > 1) return 1;
return num;
};
//#endregion
export { parseAccept };