Files
dwg-dxf-viewer-sample/apps/viewer-2d-sample/src/cadInputPolicy.ts
T

73 lines
2.1 KiB
TypeScript

export const MAX_CAD_BYTES = 50 * 1024 * 1024;
export const CAD_FETCH_TIMEOUT_MS = 15_000;
export function assertCadByteLength(byteLength: number): void {
if (!Number.isFinite(byteLength) || byteLength < 0) {
throw new Error('CAD 파일 크기를 확인할 수 없습니다.');
}
if (byteLength > MAX_CAD_BYTES) {
throw new Error('CAD 파일은 50 MiB 이하여야 합니다.');
}
}
export function resolveCadUrl(input: string, base: URL): URL {
const url = new URL(input, base);
if (!['http:', 'https:'].includes(url.protocol)) {
throw new Error('CAD URL은 HTTP(S)만 허용합니다.');
}
if (url.origin !== base.origin) {
throw new Error('CAD URL은 viewer와 같은 origin만 허용합니다.');
}
return url;
}
export async function fetchCadBuffer(url: URL): Promise<ArrayBuffer> {
const controller = new AbortController();
const timeout = window.setTimeout(() => controller.abort(), CAD_FETCH_TIMEOUT_MS);
try {
const response = await fetch(url, {
credentials: 'same-origin',
signal: controller.signal,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const declaredLength = Number(response.headers.get('content-length'));
if (Number.isFinite(declaredLength) && declaredLength > 0) {
assertCadByteLength(declaredLength);
}
if (!response.body) {
const buffer = await response.arrayBuffer();
assertCadByteLength(buffer.byteLength);
return buffer;
}
const reader = response.body.getReader();
const chunks: Uint8Array[] = [];
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
total += value.byteLength;
assertCadByteLength(total);
chunks.push(value);
}
const data = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) {
data.set(chunk, offset);
offset += chunk.byteLength;
}
return data.buffer;
} catch (error) {
if (controller.signal.aborted) {
throw new Error('CAD 파일 요청 시간이 초과되었습니다.');
}
throw error;
} finally {
window.clearTimeout(timeout);
}
}