import { IService, Request, Response, Service } from "../../../mod.ts";import { createHash } from "./deps.ts";
export class ETagService extends Service implements IService { #options: { weak: boolean };
#etags: Map<string, string> = new Map();
constructor(options: { weak: boolean } = { weak: false }) { super(); this.#options = options; }
runAfterResource(request: Request, response: Response) { if ( response.body === null || (typeof response.body === "string" && response.body.length === 0) ) {
const header = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'; if (request.headers.get("if-none-match")) { response.status = 304; response.body = null; const existingModifiedDate = this.#etags.get(header) as string; response.headers.set("last-modified", existingModifiedDate); } else { const date = new Date().toUTCString(); response.headers.set("last-modified", date); this.#etags.set(header, date); } response.headers.set("etag", header); return; }
const body = typeof response.body === "string" ? new TextEncoder().encode(response.body) : response.body as Uint8Array; const hash = createHash("sha1").update(body, "utf8").digest("base64") .toString().substring(0, 27); const len = body.byteLength;
let header = `"${len.toString(16)}-${hash}"`; if (this.#options.weak === true) { header = "W/" + header; }
response.headers.set("etag", header);
const incomingRequestIfNoneMatchValue = request.headers.get( "if-none-match", ); if (incomingRequestIfNoneMatchValue) { if (header === incomingRequestIfNoneMatchValue) { response.status = 304; response.body = null; response.headers.set( "last-modified", this.#etags.get(header) as string, ); return; } else { response.status = 200; const date = new Date().toUTCString(); this.#etags.set(header, date); response.headers.set("last-modified", date); return; } }
response.status = 200; const date = new Date().toUTCString(); this.#etags.set(header, date); response.headers.set("last-modified", date); }}