Created
October 30, 2024 01:23
-
-
Save aabccd021/d309f89d6ea950b68202f35aac91ff8d to your computer and use it in GitHub Desktop.
Bun etag middlware
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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