66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import type { TransformRequest, TransformResult } from './transformTypes';
|
|
|
|
export const TRANSFORM_LIMITS = {
|
|
maxXmlBytes: 5 * 1024 * 1024,
|
|
maxXsltBytes: 2 * 1024 * 1024,
|
|
maxOutputBytes: 10 * 1024 * 1024,
|
|
timeoutMs: 20_000,
|
|
} as const;
|
|
|
|
function utf8Bytes(value: string): number {
|
|
return new TextEncoder().encode(value).byteLength;
|
|
}
|
|
|
|
export function assertTransformInputWithinLimits(
|
|
request: TransformRequest
|
|
): void {
|
|
const xmlBytes = utf8Bytes(request.xmlText);
|
|
if (xmlBytes > TRANSFORM_LIMITS.maxXmlBytes) {
|
|
throw new Error(
|
|
`XML input exceeds the ${TRANSFORM_LIMITS.maxXmlBytes}-byte execution limit.`
|
|
);
|
|
}
|
|
|
|
const xsltBytes = utf8Bytes(request.xsltText);
|
|
if (xsltBytes > TRANSFORM_LIMITS.maxXsltBytes) {
|
|
throw new Error(
|
|
`XSLT stylesheet exceeds the ${TRANSFORM_LIMITS.maxXsltBytes}-byte execution limit.`
|
|
);
|
|
}
|
|
}
|
|
|
|
export function assertTransformOutputWithinLimits(
|
|
result: TransformResult
|
|
): void {
|
|
if (utf8Bytes(result.output) > TRANSFORM_LIMITS.maxOutputBytes) {
|
|
throw new Error(
|
|
`Transformation output exceeds the ${TRANSFORM_LIMITS.maxOutputBytes}-byte execution limit.`
|
|
);
|
|
}
|
|
}
|
|
|
|
export async function withTransformationTimeout<T>(
|
|
operation: () => Promise<T>,
|
|
timeoutMs: number = TRANSFORM_LIMITS.timeoutMs
|
|
): Promise<T> {
|
|
let timer: number | undefined;
|
|
try {
|
|
return await Promise.race([
|
|
Promise.resolve().then(operation),
|
|
new Promise<never>((_resolve, reject) => {
|
|
timer = window.setTimeout(
|
|
() =>
|
|
reject(
|
|
new Error(
|
|
`Transformation exceeded the ${timeoutMs}-millisecond execution limit.`
|
|
)
|
|
),
|
|
timeoutMs
|
|
);
|
|
}),
|
|
]);
|
|
} finally {
|
|
if (timer !== undefined) window.clearTimeout(timer);
|
|
}
|
|
}
|