Skip to content

Commit 8dec921

Browse files
committed
feat: Make CorsHandler customizable.
1 parent d6c0f89 commit 8dec921

File tree

3 files changed

+49
-12
lines changed

3 files changed

+49
-12
lines changed

config/presets/middleware.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@
66
"@type": "AllVoidCompositeHandler",
77
"AllVoidCompositeHandler:_handlers": [
88
{
9-
"@type": "CorsHandler"
9+
"@type": "CorsHandler",
10+
"CorsHandler:_options_methods": [
11+
"GET",
12+
"HEAD",
13+
"OPTIONS",
14+
"POST",
15+
"PUT",
16+
"PATCH",
17+
"DELETE"
18+
]
1019
},
1120
{
1221
"@type": "HeaderHandler",

src/server/middleware/CorsHandler.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
import cors from 'cors';
2+
import type { CorsOptions } from 'cors';
23
import type { RequestHandler } from 'express';
34
import { HttpHandler } from '../HttpHandler';
45
import type { HttpRequest } from '../HttpRequest';
56
import type { HttpResponse } from '../HttpResponse';
67

8+
const defaultOptions: CorsOptions = {
9+
origin: (origin: any, callback: any): void => callback(null, origin ?? '*'),
10+
};
11+
12+
// Components.js does not support the full CorsOptions yet
13+
interface SimpleCorsOptions {
14+
origin?: string;
15+
methods?: string[];
16+
allowedHeaders?: string[];
17+
exposedHeaders?: string[];
18+
credentials?: boolean;
19+
maxAge?: number;
20+
preflightContinue?: boolean;
21+
optionsSuccessStatus?: number;
22+
}
23+
724
/**
825
* Handler that sets CORS options on the response.
926
*/
1027
export class CorsHandler extends HttpHandler {
1128
private readonly corsHandler: RequestHandler;
1229

13-
public constructor() {
30+
public constructor(options: SimpleCorsOptions = {}) {
1431
super();
15-
this.corsHandler = cors({
16-
origin: (origin, callback): void => callback(null, (origin ?? '*') as any),
17-
methods: [ 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ],
18-
});
32+
this.corsHandler = cors({ ...defaultOptions, ...options });
1933
}
2034

2135
public async handle(input: { request: HttpRequest; response: HttpResponse }): Promise<void> {

test/unit/server/middleware/CorsHandler.test.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,45 @@ import { CorsHandler } from '../../../../src/server/middleware/CorsHandler';
33
import { guardStream } from '../../../../src/util/GuardedStream';
44

55
describe('a CorsHandler', (): void => {
6-
let handler: CorsHandler;
6+
it('sets regular CORS headers.', async(): Promise<void> => {
7+
const handler = new CorsHandler();
78

8-
beforeAll(async(): Promise<void> => {
9-
handler = new CorsHandler();
10-
});
11-
12-
it('returns CORS headers.', async(): Promise<void> => {
139
const request = guardStream(createRequest());
1410
const response = createResponse();
1511
await handler.handleSafe({ request, response });
12+
1613
expect(response.getHeaders()).toEqual(expect.objectContaining({
1714
'access-control-allow-origin': '*',
1815
}));
1916
});
2017

2118
it('echoes the origin when specified.', async(): Promise<void> => {
19+
const handler = new CorsHandler();
20+
2221
const request = guardStream(createRequest({
2322
headers: {
2423
origin: 'example.org',
2524
},
2625
}));
2726
const response = createResponse();
2827
await handler.handleSafe({ request, response });
28+
2929
expect(response.getHeaders()).toEqual(expect.objectContaining({
3030
'access-control-allow-origin': 'example.org',
3131
}));
3232
});
33+
34+
it('supports customizations.', async(): Promise<void> => {
35+
const handler = new CorsHandler({
36+
exposedHeaders: [ 'Custom-Header' ],
37+
});
38+
39+
const request = guardStream(createRequest());
40+
const response = createResponse();
41+
await handler.handleSafe({ request, response });
42+
43+
expect(response.getHeaders()).toEqual(expect.objectContaining({
44+
'access-control-expose-headers': 'Custom-Header',
45+
}));
46+
});
3347
});

0 commit comments

Comments
 (0)