From c2e002d051915ee1c416028055542ef6d0f972a1 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 27 Jul 2021 14:35:20 +1000 Subject: [PATCH] fix(runtime-handler): using set-cookie now sets cookie header Following the implementation of the Functions runtime-handler, the Response object sets the Set-Cookie header to [] if there are no cookies set. If you then set a header with the key 'set-cookie' (or any other capitalisation) it will be eventually overridden by the empty array under Set-Cookie (since it is also added to the headers last). To fix this all cookies are set under the key 'Set-Cookie'. --- .../dev-runtime/internal/response.test.ts | 16 +++++++++ .../src/dev-runtime/internal/response.ts | 33 ++++++++++--------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/runtime-handler/__tests__/dev-runtime/internal/response.test.ts b/packages/runtime-handler/__tests__/dev-runtime/internal/response.test.ts index db476e2e..8a54e45a 100644 --- a/packages/runtime-handler/__tests__/dev-runtime/internal/response.test.ts +++ b/packages/runtime-handler/__tests__/dev-runtime/internal/response.test.ts @@ -100,6 +100,22 @@ test('sets headers with an array of cookies', () => { expect(response['headers']).toEqual(expected); }); +test('sets cookies with lower case set-cookie', () => { + const response = new Response(); + expect(response['headers']).toEqual({ + 'Set-Cookie': [], + }); + response.setHeaders({ + 'Access-Control-Allow-Origin': 'example.com', + 'set-cookie': ['Hi=Bye', 'Hello=World'], + }); + const expected = { + 'Access-Control-Allow-Origin': 'example.com', + 'Set-Cookie': ['Hi=Bye', 'Hello=World'], + }; + expect(response['headers']).toEqual(expected); +}); + test('appends a new header correctly', () => { const response = new Response(); expect(response['headers']).toEqual({ diff --git a/packages/runtime-handler/src/dev-runtime/internal/response.ts b/packages/runtime-handler/src/dev-runtime/internal/response.ts index 9e55faf2..20ec8285 100644 --- a/packages/runtime-handler/src/dev-runtime/internal/response.ts +++ b/packages/runtime-handler/src/dev-runtime/internal/response.ts @@ -59,15 +59,10 @@ export class Response implements TwilioResponse { if (typeof headersObject !== 'object') { return this; } - if (!(COOKIE_HEADER in headersObject)) { - headersObject[COOKIE_HEADER] = []; - } - - const cookieHeader = headersObject[COOKIE_HEADER]; - if (!Array.isArray(cookieHeader)) { - headersObject[COOKIE_HEADER] = [cookieHeader]; + this.headers = {}; + for (const header in headersObject) { + this.appendHeader(header, headersObject[header]); } - this.headers = headersObject; return this; } @@ -75,16 +70,24 @@ export class Response implements TwilioResponse { appendHeader(key: string, value: HeaderValue): Response { log('Appending header for %s', key, value); this.headers = this.headers || {}; - const existingValue = this.headers[key]; let newHeaderValue: HeaderValue = []; - if (existingValue) { - newHeaderValue = [existingValue, value].flat(); - if (newHeaderValue) { - this.headers[key] = newHeaderValue; + if (key.toLowerCase() === COOKIE_HEADER.toLowerCase()) { + const existingValue = this.headers[COOKIE_HEADER]; + if (existingValue) { + newHeaderValue = [existingValue, value].flat(); + if (newHeaderValue) { + this.headers[COOKIE_HEADER] = newHeaderValue; + } + } else { + this.headers[COOKIE_HEADER] = Array.isArray(value) ? value: [value]; } } else { - if (key === COOKIE_HEADER && !Array.isArray(value)) { - this.headers[key] = [value]; + const existingValue = this.headers[key]; + if (existingValue) { + newHeaderValue = [existingValue, value].flat(); + if (newHeaderValue) { + this.headers[key] = newHeaderValue; + } } else { this.headers[key] = value; }