🐞 Problem (Bug)
In the direct upload route (PUT /:fileKey), if the client sends the file using the multipart/form-data encoding (which can happen with certain libraries or proxies), the server incorrectly saves the entire multipart/form-data body—including form headers and boundary delimiters (--WebKitFormBoundary...)—instead of saving only the clean file bytes.
💥 Impact
Files downloaded later via the public access route (GET /f/:fileKey) are corrupted, displaying as a text dump of the multipart/form-data structure instead of the intended file content (e.g., a PNG image fails to display).
The effective file size in the storage backend is inflated due to the inclusion of unnecessary form metadata.
🔍 Root Cause
The original implementation relied solely on const blob = await c.req.blob();. When a request arrived with Content-Type: multipart/form-data, this method read the entire request body (the form packet) as a single binary Blob. This included all the form's structural text, leading to the corruption when saved.
✅ Solution
Implement explicit content type checking. If the Content-Type is multipart/form-data, the code must use the specialized form parser (c.req.formData()) to extract the clean File object (which is a Blob) before passing it to the storage adapter.
Code Fix (Diff):
// Original, problematic code:
// const blob = await c.req.blob();
// New, corrected block:
let blob: Blob;
const contentType = c.req.header("content-type") || "";
if (contentType.includes("multipart/form-data")) {
const formData = await c.req.formData();
const file = formData.get("file");
if (!file || !(file instanceof File)) {
return c.json({ error: "No file provided" }, 400);
}
// Extract the clean File/Blob object from the FormData
blob = file;
} else {
// Handle the ideal case: pure binary PUT (clean bytes)
blob = await c.req.blob();
}
const { fileHash } = await storageAdapter.upload(fileKey, blob);
🐞 Problem (Bug)
In the direct upload route (
PUT /:fileKey), if the client sends the file using themultipart/form-dataencoding (which can happen with certain libraries or proxies), the server incorrectly saves the entiremultipart/form-databody—including form headers and boundary delimiters (--WebKitFormBoundary...)—instead of saving only the clean file bytes.💥 Impact
Files downloaded later via the public access route (
GET /f/:fileKey) are corrupted, displaying as a text dump of themultipart/form-datastructure instead of the intended file content (e.g., a PNG image fails to display).The effective file size in the storage backend is inflated due to the inclusion of unnecessary form metadata.
🔍 Root Cause
The original implementation relied solely on
const blob = await c.req.blob();. When a request arrived withContent-Type: multipart/form-data, this method read the entire request body (the form packet) as a single binary Blob. This included all the form's structural text, leading to the corruption when saved.✅ Solution
Implement explicit content type checking. If the Content-Type is multipart/form-data, the code must use the specialized form parser (
c.req.formData()) to extract the clean File object (which is a Blob) before passing it to the storage adapter.Code Fix (Diff):