Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions src/helper/cookie/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,4 +498,121 @@ describe('Cookie Middleware', () => {
)
})
})

describe('getCookie after setCookie', () => {
it('should return the newly set cookie value', async () => {
const app = new Hono()

app.get('/test', (c) => {
setCookie(c, 'session', 'abc123')
const value = getCookie(c, 'session')
return c.text(value || 'not found')
})

const res = await app.request('http://localhost/test')
expect(res.status).toBe(200)
expect(await res.text()).toBe('abc123')
})

it('should override request cookie with newly set cookie', async () => {
const app = new Hono()

app.get('/test', (c) => {
setCookie(c, 'session', 'new_value')
const value = getCookie(c, 'session')
return c.text(value || 'not found')
})

const req = new Request('http://localhost/test')
req.headers.set('Cookie', 'session=old_value')
const res = await app.request(req)
expect(res.status).toBe(200)
expect(await res.text()).toBe('new_value')
})

it('should return all cookies including newly set ones', async () => {
const app = new Hono()

app.get('/test', (c) => {
setCookie(c, 'new_cookie', 'new_value')
const cookies = getCookie(c)
return c.json(cookies)
})

const req = new Request('http://localhost/test')
req.headers.set('Cookie', 'existing=hello')
const res = await app.request(req)
const body = await res.json()
expect(body).toEqual({ existing: 'hello', new_cookie: 'new_value' })
})

it('should return set cookie when no request cookies exist', async () => {
const app = new Hono()

app.get('/test', (c) => {
setCookie(c, 'token', 'xyz')
const value = getCookie(c, 'token')
return c.text(value || 'not found')
})

const res = await app.request('http://localhost/test')
expect(await res.text()).toBe('xyz')
})
})

describe('getSignedCookie after setSignedCookie', () => {
const secret = 'secret chocolate chips'

it('should return the newly set signed cookie value', async () => {
const app = new Hono()

app.get('/test', async (c) => {
await setSignedCookie(c, 'session', 'abc123', secret)
const value = await getSignedCookie(c, secret, 'session')
return c.text(value || 'not found')
})

const res = await app.request('http://localhost/test')
expect(res.status).toBe(200)
expect(await res.text()).toBe('abc123')
})

it('should override request signed cookie with newly set signed cookie', async () => {
const app = new Hono()

app.get('/test', async (c) => {
await setSignedCookie(c, 'session', 'new_value', secret)
const value = await getSignedCookie(c, secret, 'session')
return c.text(value || 'not found')
})

const req = new Request('http://localhost/test')
req.headers.set(
'Cookie',
'session=old_value.diubJPY8O7hI1pLa42QSfkPiyDWQ0I4DnlACH%2FN2HaA%3D'
)
const res = await app.request(req)
expect(res.status).toBe(200)
expect(await res.text()).toBe('new_value')
})

it('should return all signed cookies including newly set ones', async () => {
const app = new Hono()

app.get('/test', async (c) => {
await setSignedCookie(c, 'new_cookie', 'new_value', secret)
const cookies = await getSignedCookie(c, secret)
return c.json(cookies)
})

const req = new Request('http://localhost/test')
req.headers.set(
'Cookie',
'existing=hello.Z9v8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F8%2F'
)
const res = await app.request(req)
const body = await res.json()
expect(body.new_cookie).toBe('new_value')
})
})
})
37 changes: 29 additions & 8 deletions src/helper/cookie/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,28 @@ interface GetSignedCookie {
): Promise<string | undefined | false>
}

const getSetCookieString = (c: Context): string => {
const setCookieHeaders = c.res.headers.getSetCookie()
return setCookieHeaders
.map((s) => {
const eqIdx = s.indexOf('=')
if (eqIdx === -1) {
return ''
}
const semiIdx = s.indexOf(';', eqIdx)
return semiIdx === -1 ? s : s.substring(0, semiIdx)
})
.filter(Boolean)
.join('; ')
}

export const getCookie: GetCookie = (c, key?, prefix?: CookiePrefixOptions) => {
const cookie = c.req.raw.headers.get('Cookie')
const setCookie = getSetCookieString(c)
const combinedCookie = [setCookie, cookie].filter(Boolean).join('; ')

if (typeof key === 'string') {
if (!cookie) {
if (!combinedCookie) {
return undefined
}
let finalKey = key
Expand All @@ -36,13 +54,13 @@ export const getCookie: GetCookie = (c, key?, prefix?: CookiePrefixOptions) => {
} else if (prefix === 'host') {
finalKey = '__Host-' + key
}
const obj = parse(cookie, finalKey)
const obj = parse(combinedCookie, finalKey)
return obj[finalKey]
}
if (!cookie) {
if (!combinedCookie) {
return {}
}
const obj = parse(cookie)
const obj = parse(combinedCookie)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return obj as any
}
Expand All @@ -54,8 +72,11 @@ export const getSignedCookie: GetSignedCookie = async (
prefix?: CookiePrefixOptions
) => {
const cookie = c.req.raw.headers.get('Cookie')
const setCookie = getSetCookieString(c)
const combinedCookie = [setCookie, cookie].filter(Boolean).join('; ')

if (typeof key === 'string') {
if (!cookie) {
if (!combinedCookie) {
return undefined
}
let finalKey = key
Expand All @@ -64,13 +85,13 @@ export const getSignedCookie: GetSignedCookie = async (
} else if (prefix === 'host') {
finalKey = '__Host-' + key
}
const obj = await parseSigned(cookie, secret, finalKey)
const obj = await parseSigned(combinedCookie, secret, finalKey)
return obj[finalKey]
}
if (!cookie) {
if (!combinedCookie) {
return {}
}
const obj = await parseSigned(cookie, secret)
const obj = await parseSigned(combinedCookie, secret)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return obj as any
}
Expand Down
Loading