Skip to content

Commit d512856

Browse files
committed
fix(share): declare the resolved media type, not the stored one
Follow-on to the previous commit, and a hole that commit opened. Widening `isMedia` to admit filename-detected media let an `application/octet-stream` `.mp4` into the byte-range branch — but the response still declared `contentType: file.contentType`. These responses are `nosniff`, so the browser saw `application/octet-stream` and refused to render, and `getSecureFileHeaders` derives disposition from that same value, so it also came back as `attachment`. The file became seekable and still would not play. The fix moved the failure instead of removing it. The declared type is now resolved alongside the admission decision: the stored type wins when it is already audio/video (more specific — `video/webm` beats a filename guess), otherwise the filename-derived type that admitted the file. Header and disposition both follow it. The buffered branch sixty lines below already resolved its type this way, with a comment naming this exact hazard. I widened the predicate without reading it. Suite: 20951 passed. files API: 267 passed.
1 parent c0dc91e commit d512856

1 file changed

Lines changed: 16 additions & 4 deletions

File tree

  • apps/sim/app/api/files/public/[token]/content

apps/sim/app/api/files/public/[token]/content/route.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,21 @@ export const GET = withRouteHandler(
7979
* a shared `.mp4` silently lost `Accept-Ranges` while the very same file
8080
* stayed seekable inside the workspace.
8181
*/
82-
const isMedia =
83-
isMediaContentType(file.contentType) ||
84-
isMediaContentType(getContentType(file.originalName))
82+
const storedIsMedia = isMediaContentType(file.contentType)
83+
const filenameContentType = getContentType(file.originalName)
84+
const isMedia = storedIsMedia || isMediaContentType(filenameContentType)
85+
86+
/**
87+
* What the media branch actually declares. The stored type wins when it is
88+
* already audio/video — it is the more specific answer — otherwise the
89+
* filename-derived one, which is what admitted the file in the first place.
90+
*
91+
* Emitting the stored type unconditionally would defeat the widening above:
92+
* these responses are `nosniff`, so an `application/octet-stream` `.mp4`
93+
* would enter the byte-range branch and still refuse to play. The buffered
94+
* branch below resolves the type the same way, for the same reason.
95+
*/
96+
const mediaContentType = storedIsMedia ? file.contentType : filenameContentType
8597

8698
/**
8799
* The share is only known after the token resolves, so the aggregate
@@ -149,7 +161,7 @@ export const GET = withRouteHandler(
149161
return await createByteRangeResponse({
150162
openStream: (range) => downloadFileStream({ key: file.key, context: 'workspace', range }),
151163
size: head.size,
152-
contentType: file.contentType,
164+
contentType: mediaContentType,
153165
filename: file.originalName,
154166
cacheControl: 'private, no-cache, must-revalidate',
155167
rangeHeader,

0 commit comments

Comments
 (0)