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 | 1x 1x 1x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 2x 2x 1x 1x 1x 9x 9x 9x 9x 3x 3x 3x | import type * as http from 'http';
export interface CorsOpts {
/**
* Value of the `Access-Control-Allow-Origin` header, `'*'` by default. Set to
* `true` to echo back the request `Origin` header instead, which is what
* browsers require when credentials are enabled.
*/
origin?: string | true;
/** Value of `Access-Control-Allow-Methods`, sent on preflight responses. */
methods?: string;
/**
* Value of `Access-Control-Allow-Headers`, sent on preflight responses. Must
* list `Content-Type`: the `application/x.rpc.*` media types this server
* negotiates are not CORS-safelisted, so the preflight fails without it.
*/
headers?: string;
/** Value of `Access-Control-Expose-Headers`. Omitted when empty. */
expose?: string;
/** Whether to send `Access-Control-Allow-Credentials: true`. */
credentials?: boolean;
/** Value of `Access-Control-Max-Age`, in seconds. Defaults to 86400. */
maxAge?: number;
}
const DEFAULT_METHODS = 'GET, POST, PUT, DELETE, PATCH, OPTIONS';
const DEFAULT_HEADERS = 'Content-Type, Authorization';
export class Http1Cors {
public readonly origin: string;
public readonly echo: boolean;
public readonly credentials: boolean;
public readonly methods: string;
public readonly headers: string;
public readonly expose: string;
public readonly maxAge: string;
constructor(opts: CorsOpts = {}) {
const credentials = !!opts.credentials;
const origin = opts.origin ?? '*';
// Browsers reject a wildcard origin on a credentialed response.
const echo = origin === true || (credentials && origin === '*');
this.echo = echo;
this.origin = echo ? '' : (origin as string);
this.credentials = credentials;
this.methods = opts.methods ?? DEFAULT_METHODS;
this.headers = opts.headers ?? DEFAULT_HEADERS;
this.expose = opts.expose ?? '';
this.maxAge = String(opts.maxAge ?? 86400);
}
/** Headers every cross-origin response needs, preflight or not. */
public apply(req: http.IncomingMessage, res: http.ServerResponse): void {
let origin = this.origin;
if (this.echo) {
const header = req.headers.origin;
if (typeof header !== 'string') return;
origin = header;
const vary = res.getHeader('Vary');
res.setHeader('Vary', vary ? vary + ', Origin' : 'Origin');
}
res.setHeader('Access-Control-Allow-Origin', origin);
if (this.credentials) res.setHeader('Access-Control-Allow-Credentials', 'true');
const expose = this.expose;
if (expose) res.setHeader('Access-Control-Expose-Headers', expose);
}
/** Headers only a preflight response needs, on top of {@link Http1Cors.apply}. */
public preflight(res: http.ServerResponse): void {
res.setHeader('Access-Control-Allow-Methods', this.methods);
res.setHeader('Access-Control-Allow-Headers', this.headers);
res.setHeader('Access-Control-Max-Age', this.maxAge);
}
}
|