Skip to content

Instantly share code, notes, and snippets.

@aabccd021
Created October 30, 2024 01:23
Show Gist options
  • Save aabccd021/d309f89d6ea950b68202f35aac91ff8d to your computer and use it in GitHub Desktop.
Save aabccd021/d309f89d6ea950b68202f35aac91ff8d to your computer and use it in GitHub Desktop.
Bun etag middlware
type RequestHandler = (req: Request) => Promise<Response>;
export const retainedHeaders = [
"cache-control",
"content-location",
"date",
"etag",
"expires",
"vary",
];
function create304Response(response: Response): Response {
for (const header of response.headers.keys()) {
if (!retainedHeaders.includes(header)) {
response.headers.delete(header);
}
}
return new Response(undefined, {
status: 304,
// headers should be kept
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304
headers: response.headers,
});
}
function etagMatches(etag: string, ifNoneMatch: string | null): boolean {
if (ifNoneMatch === null) {
return false;
}
return ifNoneMatch.split(", ").includes(etag);
}
export function middleware(handle: RequestHandler): RequestHandler {
return async (req) => {
const ifNoneMatch = req.headers.get("If-None-Match");
// https://github.com/bogeychan/elysia-etag/blob/master/src/index.ts
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304
const isGetOrHead = req.method === "GET" || req.method === "HEAD";
if (ifNoneMatch !== null && !isGetOrHead) {
return new Response(undefined, { status: 412 });
}
const response = await handle(req);
if (response.body === null) {
return response;
}
const headerEtag = response.headers.get("ETag");
if (headerEtag !== null) {
if (etagMatches(headerEtag, ifNoneMatch)) {
return create304Response(response);
}
return response;
}
const mime = response.headers.get("Content-Type")?.split(";")[0];
if (mime === undefined) {
return response;
}
// what else?
if (mime === "text/event-stream") {
return response;
}
const body = await response.arrayBuffer();
const etag = Bun.hash(body).toString();
if (etagMatches(etag, ifNoneMatch)) {
return create304Response(response);
}
const newResponse = new Response(body, response);
newResponse.headers.set("ETag", etag);
return newResponse;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment