Repository: solid/community-server (ts)

Issue:
Calling OPTIONS method causes error on server
Based on latest main code:
```
npm start
curl -i -X OPTIONS http://localhost:3000/
```
The server log reports:
```
2021-02-04T10:51:59.965Z [ExpressHttpServerFactory] error: Error: Cannot set headers after they are sent to the client
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:558:11)
    at HeaderHandler.handle (/Users/pete/work/solid/community-server/dist/server/middleware/HeaderHandler.js:15:22)
    at /Users/pete/work/solid/community-server/dist/util/handlers/ParallelHandler.js:19:67
    at Array.map (<anonymous>)
    at ParallelHandler.handle (/Users/pete/work/solid/community-server/dist/util/handlers/ParallelHandler.js:19:42)
    at SequenceHandler.handle (/Users/pete/work/solid/community-server/dist/util/handlers/SequenceHandler.js:27:40)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async /Users/pete/work/solid/community-server/dist/server/ExpressHttpServerFactory.js:24:17
```
The response seems OK: 
```
HTTP/1.1 204 No Content
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET,HEAD,OPTIONS,POST,PUT,PATCH,DELETE
Vary: Access-Control-Request-Headers
Access-Control-Expose-Headers: Accept-Patch,Location,MS-Author-Via,Updates-Via
Content-Length: 0
Date: Thu, 04 Feb 2021 10:51:59 GMT
Connection: keep-alive
Keep-Alive: timeout=5
```

Pull request description:
fix: Prevent race condition in OPTIONS call
Closes #591 

Patch:
diff --git a/config/presets/middleware.json b/config/presets/middleware.json
index b0bbad02e..44b26222d 100644
--- a/config/presets/middleware.json
+++ b/config/presets/middleware.json
@@ -3,27 +3,8 @@
   "@graph": [
     {
       "@id": "urn:solid-server:default:Middleware",
-      "@type": "ParallelHandler",
-      "ParallelHandler:_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": "SequenceHandler",
+      "SequenceHandler:_handlers": [
         {
           "@type": "HeaderHandler",
           "HeaderHandler:_headers": [
@@ -42,6 +23,25 @@
           "WebSocketAdvertiser:_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"
+          ]
         }
       ]
     }
diff --git a/src/server/middleware/CorsHandler.ts b/src/server/middleware/CorsHandler.ts
index 23365a695..6bf8c4e61 100644
--- a/src/server/middleware/CorsHandler.ts
+++ b/src/server/middleware/CorsHandler.ts
@@ -22,6 +22,7 @@ interface SimpleCorsOptions {
 
 /**
  * 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,
  * the browser allows Solid apps to send any request and combination of request headers to the data pod,


Test patch:
diff --git a/test/integration/Middleware.test.ts b/test/integration/Middleware.test.ts
index 323260043..76acbdbf7 100644
--- a/test/integration/Middleware.test.ts
+++ b/test/integration/Middleware.test.ts
@@ -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)
       .options('/')
       .set('Access-Control-Allow-Credentials', 'true')
@@ -73,7 +73,13 @@ describe('An Express server with middleware', (): void => {
     expect(res.header).toEqual(expect.objectContaining({
       'access-control-allow-origin': '*',
       '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(',')
       .map((method: string): string => method.trim());
     const allowedMethods = [ 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ];