fix: support cookies with empty value (#9376)
This commit is contained in:
parent
0713cb3d39
commit
9164fc71ef
|
|
@ -327,7 +327,7 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
|
|
||||||
async storageState(): Promise<types.StorageState> {
|
async storageState(): Promise<types.StorageState> {
|
||||||
const result: types.StorageState = {
|
const result: types.StorageState = {
|
||||||
cookies: (await this.cookies()).filter(c => c.value !== ''),
|
cookies: await this.cookies(),
|
||||||
origins: []
|
origins: []
|
||||||
};
|
};
|
||||||
if (this._origins.size) {
|
if (this._origins.size) {
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,6 @@ export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): t
|
||||||
const parsedURLs = urls.map(s => new URL(s));
|
const parsedURLs = urls.map(s => new URL(s));
|
||||||
// Chromiums's cookies are missing sameSite when it is 'None'
|
// Chromiums's cookies are missing sameSite when it is 'None'
|
||||||
return cookies.filter(c => {
|
return cookies.filter(c => {
|
||||||
// Firefox and WebKit can return cookies with empty values.
|
|
||||||
if (!c.value)
|
|
||||||
return false;
|
|
||||||
if (!parsedURLs.length)
|
if (!parsedURLs.length)
|
||||||
return true;
|
return true;
|
||||||
for (const parsedURL of parsedURLs) {
|
for (const parsedURL of parsedURLs) {
|
||||||
|
|
@ -50,7 +47,6 @@ export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): t
|
||||||
export function rewriteCookies(cookies: types.SetNetworkCookieParam[]): types.SetNetworkCookieParam[] {
|
export function rewriteCookies(cookies: types.SetNetworkCookieParam[]): types.SetNetworkCookieParam[] {
|
||||||
return cookies.map(c => {
|
return cookies.map(c => {
|
||||||
assert(c.name, 'Cookie should have a name');
|
assert(c.name, 'Cookie should have a name');
|
||||||
assert(c.value, 'Cookie should have a value');
|
|
||||||
assert(c.url || (c.domain && c.path), 'Cookie should have a url or a domain/path pair');
|
assert(c.url || (c.domain && c.path), 'Cookie should have a url or a domain/path pair');
|
||||||
assert(!(c.url && c.domain), 'Cookie should have either url or domain');
|
assert(!(c.url && c.domain), 'Cookie should have either url or domain');
|
||||||
assert(!(c.url && c.path), 'Cookie should have either url or path');
|
assert(!(c.url && c.path), 'Cookie should have either url or path');
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,24 @@ it('should work with expires=-1', async ({ context, page }) => {
|
||||||
expect(await page.evaluate(() => document.cookie)).toEqual('username=John Doe');
|
expect(await page.evaluate(() => document.cookie)).toEqual('username=John Doe');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should add cookies with empty value', async ({ context, page, server }) => {
|
||||||
|
await context.addCookies([{
|
||||||
|
name: 'marker',
|
||||||
|
value: '',
|
||||||
|
domain: 'www.example.com',
|
||||||
|
path: '/',
|
||||||
|
expires: -1,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: false,
|
||||||
|
sameSite: 'Lax',
|
||||||
|
}]);
|
||||||
|
await page.route('**/*', route => {
|
||||||
|
route.fulfill({ body: '<html></html>' }).catch(() => {});
|
||||||
|
});
|
||||||
|
await page.goto('https://www.example.com');
|
||||||
|
expect(await page.evaluate(() => document.cookie)).toEqual('marker=');
|
||||||
|
});
|
||||||
|
|
||||||
it('should roundtrip cookie', async ({ context, page, server }) => {
|
it('should roundtrip cookie', async ({ context, page, server }) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
// @see https://en.wikipedia.org/wiki/Year_2038_problem
|
// @see https://en.wikipedia.org/wiki/Year_2038_problem
|
||||||
|
|
|
||||||
|
|
@ -202,14 +202,19 @@ it('should work with subdomain cookie', async ({ context, browserName, isWindows
|
||||||
}]);
|
}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not return cookies with empty value', async ({ context, page, server }) => {
|
it('should return cookies with empty value', async ({ context, page, server }) => {
|
||||||
server.setRoute('/empty.html', (req, res) => {
|
server.setRoute('/empty.html', (req, res) => {
|
||||||
res.setHeader('Set-Cookie', 'name=;Path=/');
|
res.setHeader('Set-Cookie', 'name=;Path=/');
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
const cookies = await context.cookies();
|
const cookies = await context.cookies();
|
||||||
expect(cookies.length).toBe(0);
|
expect(cookies).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: 'name',
|
||||||
|
value: ''
|
||||||
|
})
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return secure cookies based on HTTP(S) protocol', async ({ context, browserName, isWindows }) => {
|
it('should return secure cookies based on HTTP(S) protocol', async ({ context, browserName, isWindows }) => {
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,23 @@ it('should add cookies from Set-Cookie header', async ({ context, page, server }
|
||||||
expect((await page.evaluate(() => document.cookie)).split(';').map(s => s.trim()).sort()).toEqual(['foo=bar', 'session=value']);
|
expect((await page.evaluate(() => document.cookie)).split(';').map(s => s.trim()).sort()).toEqual(['foo=bar', 'session=value']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support cookie with empty value', async ({ context, page, server }) => {
|
||||||
|
server.setRoute('/setcookie.html', (req, res) => {
|
||||||
|
res.setHeader('Set-Cookie', ['first=']);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
await context.request.get(server.PREFIX + '/setcookie.html');
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
expect(await page.evaluate(() => document.cookie)).toBe('first=');
|
||||||
|
const cookies = await context.cookies();
|
||||||
|
expect(cookies.map(c => ({ name: c.name, value: c.value }))).toEqual([
|
||||||
|
{
|
||||||
|
name: 'first',
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not lose body while handling Set-Cookie header', async ({ context, server }) => {
|
it('should not lose body while handling Set-Cookie header', async ({ context, server }) => {
|
||||||
server.setRoute('/setcookie.html', (req, res) => {
|
server.setRoute('/setcookie.html', (req, res) => {
|
||||||
res.setHeader('Set-Cookie', ['session=value', 'foo=bar; max-age=3600']);
|
res.setHeader('Set-Cookie', ['session=value', 'foo=bar; max-age=3600']);
|
||||||
|
|
|
||||||
|
|
@ -103,3 +103,41 @@ it('should round-trip through the file', async ({ contextFactory }, testInfo) =>
|
||||||
expect(cookie).toEqual('username=John Doe');
|
expect(cookie).toEqual('username=John Doe');
|
||||||
await context2.close();
|
await context2.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should capture cookies', async ({ server, context, page, contextFactory }) => {
|
||||||
|
server.setRoute('/setcookie.html', (req, res) => {
|
||||||
|
res.setHeader('Set-Cookie', ['a=b', 'empty=']);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(server.PREFIX + '/setcookie.html');
|
||||||
|
expect(await page.evaluate(() => {
|
||||||
|
const cookies = document.cookie.split(';');
|
||||||
|
return cookies.map(cookie => cookie.trim()).sort();
|
||||||
|
})).toEqual([
|
||||||
|
'a=b',
|
||||||
|
'empty=',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const storageState = await context.storageState();
|
||||||
|
expect(new Set(storageState.cookies)).toEqual(new Set([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: 'a',
|
||||||
|
value: 'b'
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
name: 'empty',
|
||||||
|
value: ''
|
||||||
|
})
|
||||||
|
]));
|
||||||
|
const context2 = await contextFactory({ storageState });
|
||||||
|
const page2 = await context2.newPage();
|
||||||
|
await page2.goto(server.EMPTY_PAGE);
|
||||||
|
expect(await page2.evaluate(() => {
|
||||||
|
const cookies = document.cookie.split(';');
|
||||||
|
return cookies.map(cookie => cookie.trim()).sort();
|
||||||
|
})).toEqual([
|
||||||
|
'a=b',
|
||||||
|
'empty=',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue