mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-14 22:08:45 +00:00
파일을 업로드하는 도중에 HTTP 연결이 끊기면 서버가 크래시되던 버그 수정
This commit is contained in:
@@ -115,10 +115,8 @@ export const uploadFile = async (
|
||||
} catch (e) {
|
||||
await safeUnlink(path);
|
||||
|
||||
if (e instanceof IntegrityError) {
|
||||
if (e.message === "Inactive MEK version") {
|
||||
error(400, "Invalid MEK version");
|
||||
}
|
||||
if (e instanceof IntegrityError && e.message === "Inactive MEK version") {
|
||||
error(400, "Invalid MEK version");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
|
||||
window.alert("파일이 업로드되었어요.");
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((e: Error) => {
|
||||
// TODO: FIXME
|
||||
window.alert("파일 업로드에 실패했어요.");
|
||||
window.alert(`파일 업로드에 실패했어요.\n${e.message}`);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -6,53 +6,10 @@ import { fileUploadRequest } from "$lib/server/schemas";
|
||||
import { uploadFile } from "$lib/server/services/file";
|
||||
import type { RequestHandler } from "./$types";
|
||||
|
||||
const parseFormData = async (contentType: string, body: ReadableStream<Uint8Array>) => {
|
||||
return new Promise<{ metadata: string; content: Readable }>((resolve, reject) => {
|
||||
let metadata: string | null = null;
|
||||
let content: Readable | null = null;
|
||||
type FileMetadata = Parameters<typeof uploadFile>[0];
|
||||
|
||||
const bb = Busboy({ headers: { "content-type": contentType } });
|
||||
bb.on("field", (fieldname, val) => {
|
||||
if (fieldname !== "metadata") return reject(new Error("Invalid request body"));
|
||||
if (metadata || content) return reject(new Error("Invalid request body")); // metadata must be first
|
||||
metadata = val;
|
||||
});
|
||||
bb.on("file", (fieldname, file) => {
|
||||
if (fieldname !== "content") return reject(new Error("Invalid request body"));
|
||||
if (!metadata || content) return reject(new Error("Invalid request body")); // metadata must be first
|
||||
content = file;
|
||||
resolve({ metadata, content });
|
||||
});
|
||||
bb.on("finish", () => reject(new Error("Invalid request body")));
|
||||
bb.on("error", (e) => reject(e));
|
||||
|
||||
body.pipeTo(Writable.toWeb(bb));
|
||||
});
|
||||
};
|
||||
|
||||
export const POST: RequestHandler = async ({ locals, request }) => {
|
||||
const { userId } = await authorize(locals, "activeClient");
|
||||
|
||||
const contentTypeHeader = request.headers.get("Content-Type");
|
||||
if (!contentTypeHeader?.startsWith("multipart/form-data") || !request.body) {
|
||||
error(400, "Invalid request body");
|
||||
}
|
||||
|
||||
let metadata;
|
||||
let content;
|
||||
|
||||
try {
|
||||
const formData = await parseFormData(contentTypeHeader, request.body);
|
||||
metadata = formData.metadata;
|
||||
content = formData.content;
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.message === "Invalid request body") {
|
||||
error(400, "Invalid request body");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
const zodRes = fileUploadRequest.safeParse(JSON.parse(metadata));
|
||||
const parseFileMetadata = (userId: number, json: string) => {
|
||||
const zodRes = fileUploadRequest.safeParse(JSON.parse(json));
|
||||
if (!zodRes.success) error(400, "Invalid request body");
|
||||
const {
|
||||
parentId,
|
||||
@@ -73,25 +30,65 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
||||
if ((createdAt && !createdAtIv) || (!createdAt && createdAtIv))
|
||||
error(400, "Invalid request body");
|
||||
|
||||
await uploadFile(
|
||||
{
|
||||
userId,
|
||||
parentId,
|
||||
mekVersion,
|
||||
encDek: dek,
|
||||
dekVersion: new Date(dekVersion),
|
||||
hskVersion,
|
||||
contentHmac,
|
||||
contentType,
|
||||
encContentIv: contentIv,
|
||||
encName: name,
|
||||
encNameIv: nameIv,
|
||||
encCreatedAt: createdAt ?? null,
|
||||
encCreatedAtIv: createdAtIv ?? null,
|
||||
encLastModifiedAt: lastModifiedAt,
|
||||
encLastModifiedAtIv: lastModifiedAtIv,
|
||||
},
|
||||
content,
|
||||
);
|
||||
return text("File uploaded", { headers: { "Content-Type": "text/plain" } });
|
||||
return {
|
||||
userId,
|
||||
parentId,
|
||||
mekVersion,
|
||||
encDek: dek,
|
||||
dekVersion: new Date(dekVersion),
|
||||
hskVersion,
|
||||
contentHmac,
|
||||
contentType,
|
||||
encContentIv: contentIv,
|
||||
encName: name,
|
||||
encNameIv: nameIv,
|
||||
encCreatedAt: createdAt ?? null,
|
||||
encCreatedAtIv: createdAtIv ?? null,
|
||||
encLastModifiedAt: lastModifiedAt,
|
||||
encLastModifiedAtIv: lastModifiedAtIv,
|
||||
} satisfies FileMetadata;
|
||||
};
|
||||
|
||||
export const POST: RequestHandler = async ({ locals, request }) => {
|
||||
const { userId } = await authorize(locals, "activeClient");
|
||||
|
||||
const contentType = request.headers.get("Content-Type");
|
||||
if (!contentType?.startsWith("multipart/form-data") || !request.body) {
|
||||
error(400, "Invalid request body");
|
||||
}
|
||||
|
||||
return new Promise<Response>((resolve, reject) => {
|
||||
const bb = Busboy({ headers: { "content-type": contentType } });
|
||||
const handler =
|
||||
<T extends unknown[]>(f: (...args: T) => Promise<void>) =>
|
||||
(...args: T) => {
|
||||
f(...args).catch(reject);
|
||||
};
|
||||
|
||||
let metadata: FileMetadata | null = null;
|
||||
let content: Readable | null = null;
|
||||
|
||||
bb.on(
|
||||
"field",
|
||||
handler(async (fieldname, val) => {
|
||||
if (fieldname !== "metadata") error(400, "Invalid request body");
|
||||
if (metadata || content) error(400, "Invalid request body");
|
||||
metadata = parseFileMetadata(userId, val);
|
||||
}),
|
||||
);
|
||||
bb.on(
|
||||
"file",
|
||||
handler(async (fieldname, file) => {
|
||||
if (fieldname !== "content") error(400, "Invalid request body");
|
||||
if (!metadata || content) error(400, "Invalid request body");
|
||||
content = file;
|
||||
|
||||
await uploadFile(metadata, content);
|
||||
resolve(text("File uploaded", { headers: { "Content-Type": "text/plain" } }));
|
||||
}),
|
||||
);
|
||||
bb.on("error", (e) => content?.emit("error", e) ?? reject(e));
|
||||
|
||||
request.body!.pipeTo(Writable.toWeb(bb)).catch(() => {}); // busboy will handle the error
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user