1 line
6.2 KiB
Plaintext
1 line
6.2 KiB
Plaintext
|
{"version":3,"file":"index.js","sources":["../src/fresh.ts","../src/accepts.ts","../src/index.ts"],"sourcesContent":["import { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http'\n\nconst CACHE_CONTROL_NO_CACHE_REGEXP = /(?:^|,)\\s*?no-cache\\s*?(?:,|$)/\n\nconst compareETags = (etag: string, str: string) => str === etag || str === `W/${etag}` || `W/${str}` === etag\n\nfunction isStale(etag: string, noneMatch: string) {\n let start = 0\n let end = 0\n\n for (let i = 0, len = noneMatch.length; i < len; i++) {\n switch (noneMatch.charCodeAt(i)) {\n case 0x20 /* */:\n if (start === end) start = end = i + 1\n break\n case 0x2c /* , */:\n if (compareETags(etag, noneMatch.substring(start, end))) return false\n start = end = i + 1\n break\n default:\n end = i + 1\n break\n }\n }\n\n if (compareETags(etag, noneMatch.substring(start, end))) return false\n\n return true\n}\n\n/**\n * Check freshness of the response using request and response headers.\n */\nexport function fresh(reqHeaders: IncomingHttpHeaders, resHeaders: OutgoingHttpHeaders) {\n const modifiedSince = reqHeaders['if-modified-since']\n const noneMatch = reqHeaders['if-none-match']\n\n if (!modifiedSince && !noneMatch) return false\n\n const cacheControl = reqHeaders['cache-control']\n if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) return false\n\n // if-none-match\n if (noneMatch !== '*') {\n const etag = resHeaders.etag as string | undefined\n\n if (!etag || isStale(etag, noneMatch)) return false\n }\n\n // if-modified-since\n if (modifiedSince) {\n const lastModified = resHeaders['last-modified'] as string | undefined\n\n if (!lastModified || !(Date.parse(lastModified) <= Date.parse(modifiedSince))) return false\n }\n\n return true\n}\n","import { IncomingMessage } from 'node:http'\nimport { Accepts } from '@tinyhttp/accepts'\n\ntype Request = Pick<IncomingMessage, 'headers'>\n\ntype AcceptReturns = string | boolean | string[]\n\nexport const getAccepts =\n (req: Request) =>\n (...types: string[]): AcceptReturns =>\n new Accepts(req).types(types)\n\nexport const getAcceptsEncodings =\n (req: Request) =>\n (...encodings: string[]): AcceptReturns =>\n new Accepts(req).encodings(encodings)\n\nexport const getAcceptsCharsets =\n (req: Request) =>\n (...charsets: string[]): AcceptReturns =>\n new Accepts(req).charsets(charsets)\n\nexport const getAcceptsLanguages =\n (req: Request) =>\n (...languages: string[]): AcceptReturns =>\n new Accepts(req).languages(languages)\n","import { IncomingMessage as Request, ServerResponse as Response } from 'node:http'\nimport { Options, Ranges, Result, parseRange } from 'header-range-parser'\n\nimport { typeIs } from '@tinyhttp/type-is'\nimport { fresh } from './fresh.js'\n\nexport * from './accepts.js'\n\nexport * from '@tinyhttp/url'\n\nexport const getRequestHeader =\n (req: Pick<Request, 'headers'>) =>\n (header: string): string | string[] => {\n const lc = header.toLowerCase()\n\n switch (lc) {\n case 'referer':\n case 'referrer':\n return req.headers.referrer || req.headers.referer\n default:\n return req.headers[lc]\n }\n }\n\nexport const getRangeFromHeader =\n (req: Pick<Request, 'headers'>) =>\n (size: number, options?: Options): Result | Ranges => {\n const range = getRequestHeader(req)('Range') as string\n\n if (!range) return\n\n return parseRange(size, range, options)\n }\n\nexport const getFreshOrStale = (\n req: Pick<Request, 'headers' | 'method'>,\n res: Pick<Response, 'getHeader' | 'statusCode'>\n): boolean => {\n const method = req.method\n const status = res.statusCode\n\n // GET or HEAD for weak freshness validation only\n if (method !== 'GET' && method !== 'HEAD') return false\n\n // 2xx or 304 as per rfc2616 14.26\n if ((status >= 200 && status < 300) || status === 304) {\n return fresh(req.headers, {\n etag: res.getHeader('ETag'),\n 'last-modified': res.getHeader('Last-Modified')\n
|