Skip to content

Commit 9164fc7

Browse files
authored
fix: support cookies with empty value (microsoft#9376)
1 parent 0713cb3 commit 9164fc7

6 files changed

+81
-7
lines changed

Diff for: src/server/browserContext.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ export abstract class BrowserContext extends SdkObject {
327327

328328
async storageState(): Promise<types.StorageState> {
329329
const result: types.StorageState = {
330-
cookies: (await this.cookies()).filter(c => c.value !== ''),
330+
cookies: await this.cookies(),
331331
origins: []
332332
};
333333
if (this._origins.size) {

Diff for: src/server/network.ts

-4
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): t
2626
const parsedURLs = urls.map(s => new URL(s));
2727
// Chromiums's cookies are missing sameSite when it is 'None'
2828
return cookies.filter(c => {
29-
// Firefox and WebKit can return cookies with empty values.
30-
if (!c.value)
31-
return false;
3229
if (!parsedURLs.length)
3330
return true;
3431
for (const parsedURL of parsedURLs) {
@@ -50,7 +47,6 @@ export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): t
5047
export function rewriteCookies(cookies: types.SetNetworkCookieParam[]): types.SetNetworkCookieParam[] {
5148
return cookies.map(c => {
5249
assert(c.name, 'Cookie should have a name');
53-
assert(c.value, 'Cookie should have a value');
5450
assert(c.url || (c.domain && c.path), 'Cookie should have a url or a domain/path pair');
5551
assert(!(c.url && c.domain), 'Cookie should have either url or domain');
5652
assert(!(c.url && c.path), 'Cookie should have either url or path');

Diff for: tests/browsercontext-add-cookies.spec.ts

+18
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ it('should work with expires=-1', async ({ context, page }) => {
4545
expect(await page.evaluate(() => document.cookie)).toEqual('username=John Doe');
4646
});
4747

48+
it('should add cookies with empty value', async ({ context, page, server }) => {
49+
await context.addCookies([{
50+
name: 'marker',
51+
value: '',
52+
domain: 'www.example.com',
53+
path: '/',
54+
expires: -1,
55+
httpOnly: false,
56+
secure: false,
57+
sameSite: 'Lax',
58+
}]);
59+
await page.route('**/*', route => {
60+
route.fulfill({ body: '<html></html>' }).catch(() => {});
61+
});
62+
await page.goto('https://www.example.com');
63+
expect(await page.evaluate(() => document.cookie)).toEqual('marker=');
64+
});
65+
4866
it('should roundtrip cookie', async ({ context, page, server }) => {
4967
await page.goto(server.EMPTY_PAGE);
5068
// @see https://en.wikipedia.org/wiki/Year_2038_problem

Diff for: tests/browsercontext-cookies.spec.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,19 @@ it('should work with subdomain cookie', async ({ context, browserName, isWindows
202202
}]);
203203
});
204204

205-
it('should not return cookies with empty value', async ({ context, page, server }) => {
205+
it('should return cookies with empty value', async ({ context, page, server }) => {
206206
server.setRoute('/empty.html', (req, res) => {
207207
res.setHeader('Set-Cookie', 'name=;Path=/');
208208
res.end();
209209
});
210210
await page.goto(server.EMPTY_PAGE);
211211
const cookies = await context.cookies();
212-
expect(cookies.length).toBe(0);
212+
expect(cookies).toEqual([
213+
expect.objectContaining({
214+
name: 'name',
215+
value: ''
216+
})
217+
]);
213218
});
214219

215220
it('should return secure cookies based on HTTP(S) protocol', async ({ context, browserName, isWindows }) => {

Diff for: tests/browsercontext-fetch.spec.ts

+17
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,23 @@ it('should add cookies from Set-Cookie header', async ({ context, page, server }
229229
expect((await page.evaluate(() => document.cookie)).split(';').map(s => s.trim()).sort()).toEqual(['foo=bar', 'session=value']);
230230
});
231231

232+
it('should support cookie with empty value', async ({ context, page, server }) => {
233+
server.setRoute('/setcookie.html', (req, res) => {
234+
res.setHeader('Set-Cookie', ['first=']);
235+
res.end();
236+
});
237+
await context.request.get(server.PREFIX + '/setcookie.html');
238+
await page.goto(server.EMPTY_PAGE);
239+
expect(await page.evaluate(() => document.cookie)).toBe('first=');
240+
const cookies = await context.cookies();
241+
expect(cookies.map(c => ({ name: c.name, value: c.value }))).toEqual([
242+
{
243+
name: 'first',
244+
value: ''
245+
},
246+
]);
247+
});
248+
232249
it('should not lose body while handling Set-Cookie header', async ({ context, server }) => {
233250
server.setRoute('/setcookie.html', (req, res) => {
234251
res.setHeader('Set-Cookie', ['session=value', 'foo=bar; max-age=3600']);

Diff for: tests/browsercontext-storage-state.spec.ts

+38
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,41 @@ it('should round-trip through the file', async ({ contextFactory }, testInfo) =>
103103
expect(cookie).toEqual('username=John Doe');
104104
await context2.close();
105105
});
106+
107+
it('should capture cookies', async ({ server, context, page, contextFactory }) => {
108+
server.setRoute('/setcookie.html', (req, res) => {
109+
res.setHeader('Set-Cookie', ['a=b', 'empty=']);
110+
res.end();
111+
});
112+
113+
await page.goto(server.PREFIX + '/setcookie.html');
114+
expect(await page.evaluate(() => {
115+
const cookies = document.cookie.split(';');
116+
return cookies.map(cookie => cookie.trim()).sort();
117+
})).toEqual([
118+
'a=b',
119+
'empty=',
120+
]);
121+
122+
const storageState = await context.storageState();
123+
expect(new Set(storageState.cookies)).toEqual(new Set([
124+
expect.objectContaining({
125+
name: 'a',
126+
value: 'b'
127+
}),
128+
expect.objectContaining({
129+
name: 'empty',
130+
value: ''
131+
})
132+
]));
133+
const context2 = await contextFactory({ storageState });
134+
const page2 = await context2.newPage();
135+
await page2.goto(server.EMPTY_PAGE);
136+
expect(await page2.evaluate(() => {
137+
const cookies = document.cookie.split(';');
138+
return cookies.map(cookie => cookie.trim()).sort();
139+
})).toEqual([
140+
'a=b',
141+
'empty=',
142+
]);
143+
});

0 commit comments

Comments
 (0)