Skip to content

Incorrect File Content Saved When Using multipart/form-data on PUT Route #1

Description

@macmeharder

🐞 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);

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions