Split Set-Cookie header correctly (#30560)
## Bug
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
Fixes #30430
There's some more discussion in the issue, but in summary:
- web `Headers` implementation combines all header values with `', '`
- For `Set-Cookie` headers, you're supposed to set them as separate values, not combine them
- web `Headers` forbids the use of `Cookie`, `Set-Cookie` and some more headers, so they don't have custom implementation for those, and still joins them with `,`
- We currently just split them using `split(',')`, but this breaks when the header contains a date (expires, max-age) that also includes a `,`
I used this method to split the Set-Cookie header properly: https://www.npmjs.com/package/set-cookie-parser#splitcookiestringcombinedsetcookieheader as suggested [here](https://github.com/whatwg/fetch/issues/973#issuecomment-559678813)
I didn't add it as a dependency, since we only needed that one method and I wasn't sure what the process is for adding dependencies, so I just added the method in the middleware utils
2021-10-28 19:46:58 +02:00
|
|
|
import { splitCookiesString } from 'next/dist/server/web/utils'
|
|
|
|
import cookie, { CookieSerializeOptions } from 'next/dist/compiled/cookie'
|
|
|
|
|
|
|
|
function generateCookies(
|
|
|
|
...cookieOptions: (CookieSerializeOptions & { name: string; value: string })[]
|
|
|
|
) {
|
|
|
|
const cookies = cookieOptions.map((opts) =>
|
|
|
|
cookie.serialize(opts.name, opts.value, opts)
|
|
|
|
)
|
|
|
|
return {
|
|
|
|
joined: cookies.join(', '),
|
|
|
|
expected: cookies,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
describe('splitCookiesString', () => {
|
|
|
|
describe('with a single cookie', () => {
|
|
|
|
it('should parse a plain value', () => {
|
|
|
|
const { joined, expected } = generateCookies({
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
})
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should parse expires', () => {
|
|
|
|
const { joined, expected } = generateCookies({
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
expires: new Date(),
|
|
|
|
})
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should parse max-age', () => {
|
|
|
|
const { joined, expected } = generateCookies({
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
maxAge: 10,
|
|
|
|
})
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
2022-08-08 03:45:30 +02:00
|
|
|
it('should parse path', () => {
|
|
|
|
const { joined, expected } = generateCookies({
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
path: '/path',
|
|
|
|
})
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
Split Set-Cookie header correctly (#30560)
## Bug
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
Fixes #30430
There's some more discussion in the issue, but in summary:
- web `Headers` implementation combines all header values with `', '`
- For `Set-Cookie` headers, you're supposed to set them as separate values, not combine them
- web `Headers` forbids the use of `Cookie`, `Set-Cookie` and some more headers, so they don't have custom implementation for those, and still joins them with `,`
- We currently just split them using `split(',')`, but this breaks when the header contains a date (expires, max-age) that also includes a `,`
I used this method to split the Set-Cookie header properly: https://www.npmjs.com/package/set-cookie-parser#splitcookiestringcombinedsetcookieheader as suggested [here](https://github.com/whatwg/fetch/issues/973#issuecomment-559678813)
I didn't add it as a dependency, since we only needed that one method and I wasn't sure what the process is for adding dependencies, so I just added the method in the middleware utils
2021-10-28 19:46:58 +02:00
|
|
|
it('should parse with all the options', () => {
|
|
|
|
const { joined, expected } = generateCookies({
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
expires: new Date(Date.now() + 10 * 1000),
|
|
|
|
maxAge: 10,
|
|
|
|
domain: 'https://foo.bar',
|
|
|
|
httpOnly: true,
|
|
|
|
path: '/path',
|
|
|
|
sameSite: 'lax',
|
|
|
|
secure: true,
|
|
|
|
})
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-03-29 05:53:51 +02:00
|
|
|
describe('with a multiple cookies', () => {
|
Split Set-Cookie header correctly (#30560)
## Bug
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
Fixes #30430
There's some more discussion in the issue, but in summary:
- web `Headers` implementation combines all header values with `', '`
- For `Set-Cookie` headers, you're supposed to set them as separate values, not combine them
- web `Headers` forbids the use of `Cookie`, `Set-Cookie` and some more headers, so they don't have custom implementation for those, and still joins them with `,`
- We currently just split them using `split(',')`, but this breaks when the header contains a date (expires, max-age) that also includes a `,`
I used this method to split the Set-Cookie header properly: https://www.npmjs.com/package/set-cookie-parser#splitcookiestringcombinedsetcookieheader as suggested [here](https://github.com/whatwg/fetch/issues/973#issuecomment-559678813)
I didn't add it as a dependency, since we only needed that one method and I wasn't sure what the process is for adding dependencies, so I just added the method in the middleware utils
2021-10-28 19:46:58 +02:00
|
|
|
it('should parse a plain value', () => {
|
|
|
|
const { joined, expected } = generateCookies(
|
|
|
|
{
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'x',
|
|
|
|
value: 'y',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should parse expires', () => {
|
|
|
|
const { joined, expected } = generateCookies(
|
|
|
|
{
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
expires: new Date(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'x',
|
|
|
|
value: 'y',
|
|
|
|
expires: new Date(),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should parse max-age', () => {
|
|
|
|
const { joined, expected } = generateCookies(
|
|
|
|
{
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
maxAge: 10,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'x',
|
|
|
|
value: 'y',
|
|
|
|
maxAge: 10,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
2022-08-08 03:45:30 +02:00
|
|
|
it('should parse path', () => {
|
|
|
|
const { joined, expected } = generateCookies(
|
|
|
|
{
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
path: '/path',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'x',
|
|
|
|
value: 'y',
|
|
|
|
path: '/path',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
|
Split Set-Cookie header correctly (#30560)
## Bug
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
Fixes #30430
There's some more discussion in the issue, but in summary:
- web `Headers` implementation combines all header values with `', '`
- For `Set-Cookie` headers, you're supposed to set them as separate values, not combine them
- web `Headers` forbids the use of `Cookie`, `Set-Cookie` and some more headers, so they don't have custom implementation for those, and still joins them with `,`
- We currently just split them using `split(',')`, but this breaks when the header contains a date (expires, max-age) that also includes a `,`
I used this method to split the Set-Cookie header properly: https://www.npmjs.com/package/set-cookie-parser#splitcookiestringcombinedsetcookieheader as suggested [here](https://github.com/whatwg/fetch/issues/973#issuecomment-559678813)
I didn't add it as a dependency, since we only needed that one method and I wasn't sure what the process is for adding dependencies, so I just added the method in the middleware utils
2021-10-28 19:46:58 +02:00
|
|
|
it('should parse with all the options', () => {
|
|
|
|
const { joined, expected } = generateCookies(
|
|
|
|
{
|
|
|
|
name: 'foo',
|
|
|
|
value: 'bar',
|
|
|
|
expires: new Date(Date.now() + 10 * 1000),
|
|
|
|
maxAge: 10,
|
|
|
|
domain: 'https://foo.bar',
|
|
|
|
httpOnly: true,
|
|
|
|
path: '/path',
|
|
|
|
sameSite: 'lax',
|
|
|
|
secure: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'x',
|
|
|
|
value: 'y',
|
|
|
|
expires: new Date(Date.now() + 20 * 1000),
|
|
|
|
maxAge: 20,
|
|
|
|
domain: 'https://x.y',
|
|
|
|
httpOnly: true,
|
|
|
|
path: '/path',
|
|
|
|
sameSite: 'strict',
|
|
|
|
secure: true,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
const result = splitCookiesString(joined)
|
|
|
|
expect(result).toEqual(expected)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|