fix: Prevent race condition in OPTIONS call

This commit is contained in:
Joachim Van Herwegen 2021-02-05 16:33:26 +01:00
parent df19aa26ef
commit 73acb9cd52
3 changed files with 29 additions and 22 deletions

View File

@ -3,27 +3,8 @@
"@graph": [ "@graph": [
{ {
"@id": "urn:solid-server:default:Middleware", "@id": "urn:solid-server:default:Middleware",
"@type": "ParallelHandler", "@type": "SequenceHandler",
"ParallelHandler:_handlers": [ "SequenceHandler:_handlers": [
{
"@type": "CorsHandler",
"CorsHandler:_options_methods": [
"GET",
"HEAD",
"OPTIONS",
"POST",
"PUT",
"PATCH",
"DELETE"
],
"CorsHandler:_options_credentials": true,
"CorsHandler:_options_exposedHeaders": [
"Accept-Patch",
"Location",
"MS-Author-Via",
"Updates-Via"
]
},
{ {
"@type": "HeaderHandler", "@type": "HeaderHandler",
"HeaderHandler:_headers": [ "HeaderHandler:_headers": [
@ -42,6 +23,25 @@
"WebSocketAdvertiser:_baseUrl": { "WebSocketAdvertiser:_baseUrl": {
"@id": "urn:solid-server:default:variable:baseUrl" "@id": "urn:solid-server:default:variable:baseUrl"
} }
},
{
"@type": "CorsHandler",
"CorsHandler:_options_methods": [
"GET",
"HEAD",
"OPTIONS",
"POST",
"PUT",
"PATCH",
"DELETE"
],
"CorsHandler:_options_credentials": true,
"CorsHandler:_options_exposedHeaders": [
"Accept-Patch",
"Location",
"MS-Author-Via",
"Updates-Via"
]
} }
] ]
} }

View File

@ -22,6 +22,7 @@ interface SimpleCorsOptions {
/** /**
* Handler that sets CORS options on the response. * Handler that sets CORS options on the response.
* In case of an OPTIONS request this handler will close the connection after adding its headers.
* *
* Solid, §7.1: "A data pod MUST implement the CORS protocol [FETCH] such that, to the extent possible, * Solid, §7.1: "A data pod MUST implement the CORS protocol [FETCH] such that, to the extent possible,
* the browser allows Solid apps to send any request and combination of request headers to the data pod, * the browser allows Solid apps to send any request and combination of request headers to the data pod,

View File

@ -62,7 +62,7 @@ describe('An Express server with middleware', (): void => {
})); }));
}); });
it('returns CORS headers for an OPTIONS request.', async(): Promise<void> => { it('returns all relevant headers for an OPTIONS request.', async(): Promise<void> => {
const res = await request(server) const res = await request(server)
.options('/') .options('/')
.set('Access-Control-Allow-Credentials', 'true') .set('Access-Control-Allow-Credentials', 'true')
@ -73,7 +73,13 @@ describe('An Express server with middleware', (): void => {
expect(res.header).toEqual(expect.objectContaining({ expect(res.header).toEqual(expect.objectContaining({
'access-control-allow-origin': '*', 'access-control-allow-origin': '*',
'access-control-allow-headers': 'content-type', 'access-control-allow-headers': 'content-type',
'updates-via': 'wss://example.pod/',
'x-powered-by': 'Community Solid Server',
})); }));
const { vary } = res.header;
expect(vary).toMatch(/(^|,)\s*Accept\s*(,|$)/iu);
expect(vary).toMatch(/(^|,)\s*Authorization\s*(,|$)/iu);
expect(vary).toMatch(/(^|,)\s*Origin\s*(,|$)/iu);
const corsMethods = res.header['access-control-allow-methods'].split(',') const corsMethods = res.header['access-control-allow-methods'].split(',')
.map((method: string): string => method.trim()); .map((method: string): string => method.trim());
const allowedMethods = [ 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ]; const allowedMethods = [ 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ];