Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 4x 4x 9x 4x 5x 5x 8x 3x 3x 8x 8x 8x 8x 8x 8x 1x 8x | /**
* CORS header helpers for the request handler
*/
import type { IncomingMessage } from 'http';
export interface CorsOptions {
/** Allowed origin(s). Use '*' for any, or a specific origin. */
origin?: string | string[];
/** Allowed methods. Default: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS */
methods?: string[];
/** Allowed request headers. */
allowedHeaders?: string[];
/** Headers exposed to the browser. */
exposeHeaders?: string[];
/** Allow credentials (cookies, authorization). When true, origin cannot be '*'. */
credentials?: boolean;
/** Max age in seconds for preflight cache. */
maxAge?: number;
}
const DEFAULT_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
const DEFAULT_ALLOWED_HEADERS = ['Content-Type', 'Authorization', 'Accept', 'Origin', 'X-Requested-With'];
export interface NormalizedCorsOptions {
origin: string | string[];
methods: string[];
allowedHeaders: string[];
exposeHeaders: string[];
credentials: boolean;
maxAge: number | undefined;
}
export function normalizeCorsOptions(cors: boolean | CorsOptions): NormalizedCorsOptions {
if (cors === true) {
return {
origin: '*',
methods: DEFAULT_METHODS,
allowedHeaders: DEFAULT_ALLOWED_HEADERS,
exposeHeaders: [],
credentials: false,
maxAge: undefined,
};
}
const opts = cors as CorsOptions;
return {
origin: opts.origin ?? '*',
methods: opts.methods ?? DEFAULT_METHODS,
allowedHeaders: opts.allowedHeaders ?? DEFAULT_ALLOWED_HEADERS,
exposeHeaders: opts.exposeHeaders ?? [],
credentials: opts.credentials ?? false,
maxAge: opts.maxAge,
};
}
function resolveOrigin(requestOrigin: string | undefined, option: string | string[]): string {
if (option === '*') return '*';
Iif (Array.isArray(option)) {
if (requestOrigin && option.includes(requestOrigin)) return requestOrigin;
return option[0] ?? '*';
}
return option;
}
export function getCorsHeaders(
req: IncomingMessage,
options: NormalizedCorsOptions
): Record<string, string> {
const requestOrigin = req.headers.origin as string | undefined;
const origin = resolveOrigin(requestOrigin, options.origin);
const headers: Record<string, string> = {
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': options.methods.join(', '),
'Access-Control-Allow-Headers': options.allowedHeaders.join(', '),
};
Iif (options.exposeHeaders.length > 0) {
headers['Access-Control-Expose-Headers'] = options.exposeHeaders.join(', ');
}
Iif (options.credentials) {
headers['Access-Control-Allow-Credentials'] = 'true';
}
if (options.maxAge != null) {
headers['Access-Control-Max-Age'] = String(options.maxAge);
}
return headers;
}
|