Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/dam-download-content-disposition-filename.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@dextinity/cms-api": patch
---

Add the file name to the `Content-Disposition` header of DAM file downloads

The header was previously set to `attachment` without a file name, so browsers derived the name of the downloaded file from the URL, which contains the file name without its extension.
4 changes: 2 additions & 2 deletions packages/api/cms-api/src/dam/files/files.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function createFilesController({ Scope: PassedScope, damBasePath }: { Sco
throw new ForbiddenException();
}

res.setHeader("Content-Disposition", "attachment");
res.attachment(file.name);

@nsams nsams Sep 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does also set mime type (see https://github.com/expressjs/express/blob/bed501c695a61886399ee622875f3be933c716d8/lib/response.js#L609), based on the file name. (which you noted in the description)

I'm not sure we should do that; doesn't it set the header twice? (two values)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried this locally, it doesnt:

image

Alternatively, we could use the content-disposition package directly. I'd prefer to not roll our own encoding/escaping.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you verify using curl, so we can see the raw output?

Alternatively, we could use the content-disposition package directly.

yes, maybe better. is that what express uses internally?

return this.streamFile(file, res, { range, overrideHeaders: { "cache-control": "max-age=31536000, private" } }); // Local caches only (1 year)
}

Expand All @@ -264,7 +264,7 @@ export function createFilesController({ Scope: PassedScope, damBasePath }: { Sco
throw new BadRequestException("Content Hash mismatch!");
}

res.setHeader("Content-Disposition", "attachment");
res.attachment(file.name);
return this.streamFile(file, res, { range, overrideHeaders: { "cache-control": "max-age=31536000, s-maxage=86400, public" } }); // Public cache, 1 year for browsers, 1 day for proxies/cdn's
}

Expand Down
Loading