Skip to content

Commit a9a4c33

Browse files
authored
Omit Content-Type header for files of unknown extension in Workers Assets (#8247)
1 parent c62973b commit a9a4c33

File tree

9 files changed

+40
-17
lines changed

9 files changed

+40
-17
lines changed

.changeset/beige-crews-wash.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@cloudflare/workers-shared": minor
3+
"miniflare": minor
4+
"wrangler": minor
5+
---
6+
7+
feat: Omits Content-Type header for files of an unknown extension in Workers Assets
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
I'm a narcissist.

fixtures/workers-with-assets/tests/index.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ describe("[Workers + Assets] dynamic site", () => {
7676
response = await fetch(`http://${ip}:${port}/lava-lamps.jpg`);
7777
expect(response.status).toBe(200);
7878
expect(response.headers.get("Content-Type")).toBe("image/jpeg");
79+
80+
response = await fetch(`http://${ip}:${port}/totallyinvalidextension.greg`);
81+
expect(response.status).toBe(200);
82+
expect(response.headers.has("Content-Type")).toBeFalsy();
7983
});
8084

8185
it("should return 405 for non-GET or HEAD requests on routes where assets exist", async ({

packages/miniflare/src/plugins/assets/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export type ManifestEntry = {
181181
};
182182

183183
export type AssetReverseMap = {
184-
[pathHash: string]: { filePath: string; contentType: string };
184+
[pathHash: string]: { filePath: string; contentType: string | null };
185185
};
186186

187187
/**

packages/miniflare/src/workers/assets/assets-kv.worker.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ export default <ExportedHandler<Env>>{
3737
);
3838
const newResponse = new Response(response.body, response);
3939
// ensure the runtime will return the metadata we need
40-
newResponse.headers.append(
41-
"cf-kv-metadata",
42-
`{"contentType": "${contentType}"}`
43-
);
40+
if (contentType !== null) {
41+
newResponse.headers.append(
42+
"cf-kv-metadata",
43+
`{"contentType": "${contentType}"}`
44+
);
45+
}
4446
return newResponse;
4547
},
4648
};

packages/workers-shared/asset-worker/src/index.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,10 @@ export default class extends WorkerEntrypoint<Env> {
187187
return true;
188188
}
189189

190-
async unstable_getByETag(
191-
eTag: string
192-
): Promise<{ readableStream: ReadableStream; contentType: string }> {
190+
async unstable_getByETag(eTag: string): Promise<{
191+
readableStream: ReadableStream;
192+
contentType: string | undefined;
193+
}> {
193194
const asset = await getAssetWithMetadataFromKV(
194195
this.env.ASSETS_KV_NAMESPACE,
195196
eTag
@@ -203,13 +204,14 @@ export default class extends WorkerEntrypoint<Env> {
203204

204205
return {
205206
readableStream: asset.value,
206-
contentType: asset.metadata?.contentType ?? "application/octet-stream",
207+
contentType: asset.metadata?.contentType,
207208
};
208209
}
209210

210-
async unstable_getByPathname(
211-
pathname: string
212-
): Promise<{ readableStream: ReadableStream; contentType: string } | null> {
211+
async unstable_getByPathname(pathname: string): Promise<{
212+
readableStream: ReadableStream;
213+
contentType: string | undefined;
214+
} | null> {
213215
const eTag = await this.unstable_exists(pathname);
214216
if (!eTag) {
215217
return null;

packages/workers-shared/asset-worker/src/utils/headers.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ import { CACHE_CONTROL_BROWSER } from "../constants";
88
*/
99
export function getHeaders(
1010
eTag: string,
11-
contentType: string,
11+
contentType: string | undefined,
1212
request: Request
1313
) {
1414
const headers = new Headers({
15-
"Content-Type": contentType,
1615
ETag: `"${eTag}"`,
1716
});
1817

18+
if (contentType !== undefined) {
19+
headers.append("Content-Type", contentType);
20+
}
21+
1922
if (isCacheable(request)) {
2023
headers.append("Cache-Control", CACHE_CONTROL_BROWSER);
2124
}

packages/workers-shared/utils/helpers.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ export const normalizeFilePath = (relativeFilepath: string) => {
1010
};
1111

1212
export const getContentType = (absFilePath: string) => {
13-
let contentType = getType(absFilePath) || "application/octet-stream";
14-
if (contentType.startsWith("text/") && !contentType.includes("charset")) {
13+
let contentType = getType(absFilePath);
14+
if (
15+
contentType &&
16+
contentType.startsWith("text/") &&
17+
!contentType.includes("charset")
18+
) {
1519
contentType = `${contentType}; charset=utf-8`;
1620
}
1721
return contentType;

packages/wrangler/src/assets.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const syncAssets = async (
138138
[(await readFile(absFilePath)).toString("base64")],
139139
manifestEntry[1].hash,
140140
{
141-
type: getContentType(absFilePath),
141+
type: getContentType(absFilePath) || "application/octet-stream",
142142
}
143143
),
144144
manifestEntry[1].hash

0 commit comments

Comments
 (0)