Skip to content

Commit

Permalink
refactor: mark delete/clear cookies as expired
Browse files Browse the repository at this point in the history
  • Loading branch information
Kikobeats committed Apr 27, 2022
1 parent fde20e0 commit c2736a6
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
47 changes: 30 additions & 17 deletions packages/next/server/web/spec-extension/cookies.ts
Expand Up @@ -19,6 +19,23 @@ const normalizeCookieOptions = (options: CookieSerializeOptions) => {
const serializeValue = (value: unknown) =>
typeof value === 'object' ? `j:${JSON.stringify(value)}` : String(value)

const serializeExpiredCookie = (
key: string,
options: CookieSerializeOptions = {}
) =>
cookie.serialize(key, '', {
expires: new Date(0),
path: '/',
...options,
})

const deserializeCookie = (input: Request | Response): string[] => {
const value = input.headers.get('set-cookie')
return value !== undefined && value !== null ? value.split(', ') : []
}

const serializeCookie = (input: string[]) => input.join(', ')

export class Cookies extends Map<string, any> {
constructor(input?: string | null) {
const parsedInput = typeof input === 'string' ? cookie.parse(input) : {}
Expand All @@ -36,13 +53,6 @@ export class Cookies extends Map<string, any> {
}
}

const deserializeCookie = (input: Request | Response): string[] => {
const value = input.headers.get('set-cookie')
return value !== undefined && value !== null ? value.split(', ') : []
}

const serializeCookie = (input: string[]) => input.join(', ')

export class NextCookies extends Cookies {
response: Request | Response

Expand All @@ -64,7 +74,7 @@ export class NextCookies extends Cookies {
if (setCookie) {
this.response.headers.set(
'set-cookie',
`${store.get(args[0])}, ${setCookie}`
[store.get(args[0]), setCookie].join(', ')
)
} else {
this.response.headers.set('set-cookie', store.get(args[0]))
Expand All @@ -75,7 +85,7 @@ export class NextCookies extends Cookies {

return store
}
delete(key: any) {
delete(key: any, options: CookieSerializeOptions = {}) {
const isDeleted = super.delete(key)

if (isDeleted) {
Expand All @@ -84,18 +94,21 @@ export class NextCookies extends Cookies {
(value) => !value.startsWith(`${key}=`)
)
)

if (setCookie) {
this.response.headers.set('set-cookie', setCookie)
} else {
this.response.headers.delete('set-cookie')
}
const expiredCookie = serializeExpiredCookie(key, options)
this.response.headers.set(
'set-cookie',
[expiredCookie, setCookie].join(', ')
)
}

return isDeleted
}
clear() {
this.response.headers.delete('set-cookie')
clear(options: CookieSerializeOptions = {}) {
const expiredCookies = Array.from(super.keys())
.map((key) => serializeExpiredCookie(key, options))
.join(', ')

if (expiredCookies) this.response.headers.set('set-cookie', expiredCookies)
return super.clear()
}
}
Expand Down
13 changes: 9 additions & 4 deletions test/unit/web-runtime/next-cookies.test.ts
Expand Up @@ -79,17 +79,17 @@ it('reflect .delete into `set-cookie`', async () => {
const firstDelete = response.cookies.delete('foo')
expect(firstDelete).toBe(true)
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
'fooz=barz; Path=/'
'foo=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT, fooz=barz; Path=/'
)

expect(response.cookies.get('foo')).toBe(undefined)

const secondDelete = response.cookies.delete('fooz')
expect(secondDelete).toBe(true)
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
undefined
'fooz=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT, foo=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'
)
expect(response.cookies.get('fooz')).toBe(undefined)

expect(response.cookies.size).toBe(0)
})

Expand All @@ -100,6 +100,11 @@ it('reflect .clear into `set-cookie`', async () => {

const response = new NextResponse()

response.cookies.clear()
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
undefined
)

response.cookies.set('foo', 'bar')
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
'foo=bar; Path=/'
Expand All @@ -113,7 +118,7 @@ it('reflect .clear into `set-cookie`', async () => {

response.cookies.clear()
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
undefined
'foo=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT, fooz=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'
)
})

Expand Down

0 comments on commit c2736a6

Please sign in to comment.