mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-16 15:08:46 +00:00
파일을 업로드하는 도중에 HTTP 연결이 끊기면 서버가 크래시되던 버그 수정
This commit is contained in:
@@ -115,11 +115,9 @@ export const uploadFile = async (
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
await safeUnlink(path);
|
await safeUnlink(path);
|
||||||
|
|
||||||
if (e instanceof IntegrityError) {
|
if (e instanceof IntegrityError && e.message === "Inactive MEK version") {
|
||||||
if (e.message === "Inactive MEK version") {
|
|
||||||
error(400, "Invalid MEK version");
|
error(400, "Invalid MEK version");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,9 +66,9 @@
|
|||||||
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
|
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
|
||||||
window.alert("파일이 업로드되었어요.");
|
window.alert("파일이 업로드되었어요.");
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e: Error) => {
|
||||||
// TODO: FIXME
|
// 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 { uploadFile } from "$lib/server/services/file";
|
||||||
import type { RequestHandler } from "./$types";
|
import type { RequestHandler } from "./$types";
|
||||||
|
|
||||||
const parseFormData = async (contentType: string, body: ReadableStream<Uint8Array>) => {
|
type FileMetadata = Parameters<typeof uploadFile>[0];
|
||||||
return new Promise<{ metadata: string; content: Readable }>((resolve, reject) => {
|
|
||||||
let metadata: string | null = null;
|
|
||||||
let content: Readable | null = null;
|
|
||||||
|
|
||||||
const bb = Busboy({ headers: { "content-type": contentType } });
|
const parseFileMetadata = (userId: number, json: string) => {
|
||||||
bb.on("field", (fieldname, val) => {
|
const zodRes = fileUploadRequest.safeParse(JSON.parse(json));
|
||||||
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));
|
|
||||||
if (!zodRes.success) error(400, "Invalid request body");
|
if (!zodRes.success) error(400, "Invalid request body");
|
||||||
const {
|
const {
|
||||||
parentId,
|
parentId,
|
||||||
@@ -73,8 +30,7 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
|||||||
if ((createdAt && !createdAtIv) || (!createdAt && createdAtIv))
|
if ((createdAt && !createdAtIv) || (!createdAt && createdAtIv))
|
||||||
error(400, "Invalid request body");
|
error(400, "Invalid request body");
|
||||||
|
|
||||||
await uploadFile(
|
return {
|
||||||
{
|
|
||||||
userId,
|
userId,
|
||||||
parentId,
|
parentId,
|
||||||
mekVersion,
|
mekVersion,
|
||||||
@@ -90,8 +46,49 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
|||||||
encCreatedAtIv: createdAtIv ?? null,
|
encCreatedAtIv: createdAtIv ?? null,
|
||||||
encLastModifiedAt: lastModifiedAt,
|
encLastModifiedAt: lastModifiedAt,
|
||||||
encLastModifiedAtIv: lastModifiedAtIv,
|
encLastModifiedAtIv: lastModifiedAtIv,
|
||||||
},
|
} satisfies FileMetadata;
|
||||||
content,
|
};
|
||||||
);
|
|
||||||
return text("File uploaded", { headers: { "Content-Type": "text/plain" } });
|
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