From 8be5ce1d83eee1cda4e5883e450f86c79bc09a82 Mon Sep 17 00:00:00 2001 From: Quentin Golsteyn Date: Sun, 9 Jun 2024 14:02:03 -0700 Subject: [PATCH] fix: invalid cookie parsing --- __tests__/cookies.unit.js | 58 +++++++++++++++++++++++++++++++++++++++ lib/request.js | 4 ++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/__tests__/cookies.unit.js b/__tests__/cookies.unit.js index 28b4223..1979361 100644 --- a/__tests__/cookies.unit.js +++ b/__tests__/cookies.unit.js @@ -299,6 +299,39 @@ describe('Cookie Tests:', function() { }) }) // end it + /** + * There is no definitive standard on what the cookie value can contain. + * The most restrictive definition I could find comes from Safari which only supports + * the ASCII character set, excluding semi-colon, comma, backslash, and white space. + * + * The % character is also ambiguous, as it is used as part of the URL encoded scheme. For the purpose of this test, we will leave this character out. + * + * @see {@link https://stackoverflow.com/a/1969339 | This StackOverflow answer which provides more context regarding the cookie value} + */ + it('Parse cookie with the entire supported set of ASCII characters', async function() { + let asciiCharacterSet = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; + + asciiCharacterSet = + asciiCharacterSet.replace(' ', '') + .replace(';', '') + .replace(',', '') + .replace('/', '') + .replace('%', ''); + + let _event = Object.assign({},event,{ + path: '/cookieParse', + multiValueHeaders: { + cookie: [`test=${asciiCharacterSet}`] + } + }) + let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) })) + expect(JSON.parse(result.body)).toEqual({ + cookies: { + test: asciiCharacterSet, + }, + }) + }) // end it + it('Parse & decode two cookies', async function() { let _event = Object.assign({},event,{ path: '/cookieParse', @@ -330,6 +363,31 @@ describe('Cookie Tests:', function() { }) }) // end it + it('Parse & decode multiple cookies with the entire supported set of ASCII characters', async function() { + let asciiCharacterSet = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; + + asciiCharacterSet = + asciiCharacterSet.replace(' ', '') + .replace(';', '') + .replace(',', '') + .replace('/', '') + .replace('%', ''); + + let _event = Object.assign({},event,{ + path: '/cookieParse', + multiValueHeaders: { + cookie: [`test=${asciiCharacterSet}; test2=${asciiCharacterSet}`] + } + }) + let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) })) + expect(JSON.parse(result.body)).toEqual({ + cookies: { + test: asciiCharacterSet, + test2: asciiCharacterSet, + }, + }) + }) // end it + }) // end parse tests describe("Clear", function() { diff --git a/lib/request.js b/lib/request.js index c021987..1696cc0 100644 --- a/lib/request.js +++ b/lib/request.js @@ -163,7 +163,9 @@ class REQUEST { this.cookies = cookies.reduce((acc, cookie) => { cookie = cookie.trim().split('='); return Object.assign(acc, { - [cookie[0]]: UTILS.parseBody(decodeURIComponent(cookie[1])), + [cookie[0]]: UTILS.parseBody( + decodeURIComponent(cookie.slice(1).join('=')) + ), }); }, {});