From 5d93d4429ef736e6d522602ed7578fc6d5a25b48 Mon Sep 17 00:00:00 2001 From: exoego Date: Fri, 1 Nov 2024 11:42:44 +0900 Subject: [PATCH 1/6] perf(helper/cookie): fast-path for a specific key --- src/utils/cookie.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/utils/cookie.ts b/src/utils/cookie.ts index 5163246de..21a4de04a 100644 --- a/src/utils/cookie.ts +++ b/src/utils/cookie.ts @@ -78,16 +78,17 @@ const validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/ export const parse = (cookie: string, name?: string): Cookie => { const pairs = cookie.trim().split(';') - return pairs.reduce((parsedCookie, pairStr) => { + const parsedCookie: Cookie = {} + for (let pairStr of pairs) { pairStr = pairStr.trim() const valueStartPos = pairStr.indexOf('=') if (valueStartPos === -1) { - return parsedCookie + continue } const cookieName = pairStr.substring(0, valueStartPos).trim() if ((name && name !== cookieName) || !validCookieNameRegEx.test(cookieName)) { - return parsedCookie + continue } let cookieValue = pairStr.substring(valueStartPos + 1).trim() @@ -96,10 +97,13 @@ export const parse = (cookie: string, name?: string): Cookie => { } if (validCookieValueRegEx.test(cookieValue)) { parsedCookie[cookieName] = decodeURIComponent_(cookieValue) + if (name) { + // Fast-path: return only the demanded-key immediately. Other keys are not needed. + break + } } - - return parsedCookie - }, {} as Cookie) + } + return parsedCookie } export const parseSigned = async ( From aa1d6d075c58eeb2897fca0459ee3a7b38a385b2 Mon Sep 17 00:00:00 2001 From: exoego Date: Fri, 1 Nov 2024 12:16:40 +0900 Subject: [PATCH 2/6] perf(helper/cookie): fast-path for a specific key not found --- src/utils/cookie.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/cookie.ts b/src/utils/cookie.ts index 21a4de04a..44b6ab98a 100644 --- a/src/utils/cookie.ts +++ b/src/utils/cookie.ts @@ -77,6 +77,10 @@ const validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/ const validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/ export const parse = (cookie: string, name?: string): Cookie => { + if (name && cookie.indexOf(name) === -1) { + // Fast-path: return immediately if the demanded-key is not in the cookie string + return {} + } const pairs = cookie.trim().split(';') const parsedCookie: Cookie = {} for (let pairStr of pairs) { From ab49303dd2d2030b4ebbe84d151fca5e7441d025 Mon Sep 17 00:00:00 2001 From: exoego Date: Fri, 1 Nov 2024 12:28:02 +0900 Subject: [PATCH 3/6] perf(helper/cookie): added test for missing case --- src/helper/cookie/index.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper/cookie/index.test.ts b/src/helper/cookie/index.test.ts index 2a70cbb0c..240ddb691 100644 --- a/src/helper/cookie/index.test.ts +++ b/src/helper/cookie/index.test.ts @@ -45,6 +45,7 @@ describe('Cookie Middleware', () => { expect(res.headers.get('Yummy-Cookie')).toBe('choco') expect(res.headers.get('Tasty-Cookie')).toBe('strawberry') + expect(res.headers.get('No-Such-Cookie')).toBeNull() }) }) @@ -95,6 +96,7 @@ describe('Cookie Middleware', () => { const res = await app.request(req) expect(res.headers.get('Fortune-Cookie')).toBe('lots-of-money') expect(res.headers.get('Fruit-Cookie')).toBe('INVALID') + expect(res.headers.get('No-Such-Cookie')).toBeNull() }) it('Get signed cookie', async () => { From 63f26ad31c3199c0be98ebd5608a783a6cf4cf62 Mon Sep 17 00:00:00 2001 From: exoego Date: Fri, 1 Nov 2024 12:43:17 +0900 Subject: [PATCH 4/6] perf(helper/cookie): fix tests --- src/helper/cookie/index.test.ts | 2 -- src/utils/cookie.test.ts | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/helper/cookie/index.test.ts b/src/helper/cookie/index.test.ts index 240ddb691..2a70cbb0c 100644 --- a/src/helper/cookie/index.test.ts +++ b/src/helper/cookie/index.test.ts @@ -45,7 +45,6 @@ describe('Cookie Middleware', () => { expect(res.headers.get('Yummy-Cookie')).toBe('choco') expect(res.headers.get('Tasty-Cookie')).toBe('strawberry') - expect(res.headers.get('No-Such-Cookie')).toBeNull() }) }) @@ -96,7 +95,6 @@ describe('Cookie Middleware', () => { const res = await app.request(req) expect(res.headers.get('Fortune-Cookie')).toBe('lots-of-money') expect(res.headers.get('Fruit-Cookie')).toBe('INVALID') - expect(res.headers.get('No-Such-Cookie')).toBeNull() }) it('Get signed cookie', async () => { diff --git a/src/utils/cookie.test.ts b/src/utils/cookie.test.ts index 84578a9c1..d156a250c 100644 --- a/src/utils/cookie.test.ts +++ b/src/utils/cookie.test.ts @@ -7,6 +7,7 @@ describe('Parse cookie', () => { const cookie: Cookie = parse(cookieString) expect(cookie['yummy_cookie']).toBe('choco') expect(cookie['tasty_cookie']).toBe('strawberry') + expect(cookie['no_such_cookie']).toBeUndefined() }) it('Should parse quoted cookie values', () => { @@ -37,6 +38,7 @@ describe('Parse cookie', () => { expect(cookie['tasty_cookie']).toBe('') expect(cookie['best_cookie']).toBe('') expect(cookie['last_cookie']).toBe('') + expect(cookie['no_such_cookie']).toBeUndefined() }) it('Should parse cookies but not process signed cookies', () => { @@ -48,6 +50,7 @@ describe('Parse cookie', () => { expect(cookie['tasty_cookie']).toBe('strawberry.I9qAeGQOvWjCEJgRPmrw90JjYpnnX2C9zoOiGSxh1Ig=') expect(cookie['great_cookie']).toBe('rating3.5') expect(cookie['best_cookie']).toBe('sugar.valueShapedLikeASignatureButIsNotASignature=') + expect(cookie['no_such_cookie']).toBeUndefined() }) it('Should ignore invalid cookie names', () => { From f7870643635f1ee4580f307f37d6834a6ee22c40 Mon Sep 17 00:00:00 2001 From: exoego Date: Fri, 1 Nov 2024 12:49:13 +0900 Subject: [PATCH 5/6] perf(helper/cookie): fix tests --- src/utils/cookie.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils/cookie.test.ts b/src/utils/cookie.test.ts index d156a250c..b0cacfaae 100644 --- a/src/utils/cookie.test.ts +++ b/src/utils/cookie.test.ts @@ -31,6 +31,14 @@ describe('Parse cookie', () => { expect(cookie['tasty_cookie']).toBeUndefined() }) + it('Should parse one cookie specified by name even if it is not found', () => { + const cookieString = 'yummy_cookie=choco; tasty_cookie = strawberry ' + const cookie: Cookie = parse(cookieString, 'no_such_cookie') + expect(cookie['yummy_cookie']).toBeUndefined() + expect(cookie['tasty_cookie']).toBeUndefined() + expect(cookie['no_such_cookie']).toBeUndefined() + }) + it('Should parse cookies with no value', () => { const cookieString = 'yummy_cookie=; tasty_cookie = ; best_cookie= ; last_cookie=""' const cookie: Cookie = parse(cookieString) From f2f32f1a625c49645d460c90a8684d04305cbf11 Mon Sep 17 00:00:00 2001 From: exoego Date: Fri, 1 Nov 2024 12:49:44 +0900 Subject: [PATCH 6/6] perf(helper/cookie): cleanup tests --- src/utils/cookie.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/utils/cookie.test.ts b/src/utils/cookie.test.ts index b0cacfaae..d8ba7e515 100644 --- a/src/utils/cookie.test.ts +++ b/src/utils/cookie.test.ts @@ -7,7 +7,6 @@ describe('Parse cookie', () => { const cookie: Cookie = parse(cookieString) expect(cookie['yummy_cookie']).toBe('choco') expect(cookie['tasty_cookie']).toBe('strawberry') - expect(cookie['no_such_cookie']).toBeUndefined() }) it('Should parse quoted cookie values', () => { @@ -46,7 +45,6 @@ describe('Parse cookie', () => { expect(cookie['tasty_cookie']).toBe('') expect(cookie['best_cookie']).toBe('') expect(cookie['last_cookie']).toBe('') - expect(cookie['no_such_cookie']).toBeUndefined() }) it('Should parse cookies but not process signed cookies', () => { @@ -58,7 +56,6 @@ describe('Parse cookie', () => { expect(cookie['tasty_cookie']).toBe('strawberry.I9qAeGQOvWjCEJgRPmrw90JjYpnnX2C9zoOiGSxh1Ig=') expect(cookie['great_cookie']).toBe('rating3.5') expect(cookie['best_cookie']).toBe('sugar.valueShapedLikeASignatureButIsNotASignature=') - expect(cookie['no_such_cookie']).toBeUndefined() }) it('Should ignore invalid cookie names', () => {