Skip to content

fix(studio-server): preserve binary bodies in file PUT/POST#1914

Open
yegor177 wants to merge 1 commit into
heygen-com:mainfrom
yegor177:fix/studio-files-binary-upload
Open

fix(studio-server): preserve binary bodies in file PUT/POST#1914
yegor177 wants to merge 1 commit into
heygen-com:mainfrom
yegor177:fix/studio-files-binary-upload

Conversation

@yegor177

@yegor177 yegor177 commented Jul 3, 2026

Copy link
Copy Markdown

Problem

PUT/POST /api/projects/:id/files/* in @hyperframes/studio-server read the request body with c.req.text() and write it with writeFileSync(path, body, "utf-8"). Any body that is not valid UTF-8 — fonts, images, any binary asset — gets its non-UTF-8 bytes replaced with U+FFFD during the decode, so the file on disk is silently corrupted (and typically inflated). The Content-Type header is ignored.

Repro

curl -X PUT -H "Content-Type: application/octet-stream" \
  --data-binary @font.otf \
  http://localhost:3002/api/projects/<id>/files/assets/font.otf
# → 200, but the file on disk has a different sha256 and a larger size

Observed with a 20 828-byte OTF font arriving as 37 041 bytes on disk; @font-face then falls back silently, which makes this painful to diagnose.

Fix

Read the raw bytes (Buffer.from(await c.req.arrayBuffer())) and write the buffer without an encoding. This is byte-exact for text bodies too (UTF-8 text round-trips unchanged), so existing text uploads keep working — no content-type sniffing needed.

Testing

  • Added a vitest case in files.test.ts: POST + PUT with bodies containing invalid-UTF-8 bytes round-trip byte-for-byte.
  • Verified on a live studio-server deployment: sha256 of an uploaded OTF/PNG now matches the source exactly; HTML/text uploads (including non-ASCII content) unchanged.

c.req.text() decodes the request body as UTF-8, replacing invalid
bytes with U+FFFD — binary uploads (fonts, images) were silently
corrupted on disk. Read the raw bytes and write the buffer instead;
byte-exact for text bodies too.
.arrayBuffer()
.then((b) => Buffer.from(b))
.catch(() => Buffer.alloc(0));
writeFileSync(res.absPath, body);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants