fix(interception): make set-cookie work in chromium (#9299)

This commit is contained in:
Yury Semikhatsky 2021-10-04 13:19:05 -07:00 committed by GitHub
parent 4171dfb57f
commit c516729544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 1 deletions

View File

@ -514,13 +514,14 @@ class RouteImpl implements network.RouteDelegate {
this._wasFulfilled = true;
const body = response.isBase64 ? response.body : Buffer.from(response.body).toString('base64');
const responseHeaders = splitSetCookieHeader(response.headers);
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
await this._client._sendMayFail('Fetch.fulfillRequest', {
requestId: this._interceptionId!,
responseCode: response.status,
responsePhrase: network.STATUS_TEXTS[String(response.status)],
responseHeaders: response.headers,
responseHeaders,
body,
});
}
@ -537,6 +538,20 @@ class RouteImpl implements network.RouteDelegate {
}
}
function splitSetCookieHeader(headers: types.HeadersArray): types.HeadersArray {
const index = headers.findIndex(({ name }) => name.toLowerCase() === 'set-cookie');
if (index === -1)
return headers;
const header = headers[index];
const values = header.value.split('\n');
if (values.length === 1)
return headers;
const result = headers.slice();
result.splice(index, 1, ...values.map(value => ({ name: header.name, value })));
return result;
}
const errorReasons: { [reason: string]: Protocol.Network.ErrorReason } = {
'aborted': 'Aborted',
'accessdenied': 'AccessDenied',

View File

@ -248,3 +248,54 @@ it('should fetch original request and fulfill', async ({ page, server, isElectro
expect(response.status()).toBe(200);
expect(await page.title()).toEqual('Woof-Woof');
});
it('should fulfill with multiple set-cookie', async ({ page, server, browserName }) => {
it.fail(browserName === 'webkit', 'Response contained invalid HTTP headers');
const cookies = ['a=b', 'c=d'];
await page.route('**/empty.html', async route => {
route.fulfill({
status: 200,
headers: {
'X-Header-1': 'v1',
'Set-Cookie': cookies.join('\n'),
'X-Header-2': 'v2',
},
body: ''
});
});
const response = await page.goto(server.EMPTY_PAGE);
expect((await page.evaluate(() => document.cookie)).split(';').map(s => s.trim()).sort()).toEqual(cookies);
expect(await response.headerValue('X-Header-1')).toBe('v1');
expect(await response.headerValue('X-Header-2')).toBe('v2');
});
it('should fulfill with fetch response that has multiple set-cookie', async ({ playwright, page, server, browserName }) => {
it.fail(browserName === 'webkit', 'Response contained invalid HTTP headers');
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', ['a=b', 'c=d']);
res.end();
});
await page.route('**/empty.html', async route => {
const request = await playwright._newRequest();
const response = await request.fetch(route.request());
route.fulfill({ response });
});
await page.goto(server.EMPTY_PAGE);
const cookie = await page.evaluate(() => document.cookie);
expect(cookie.split(';').map(s => s.trim()).sort()).toEqual(['a=b', 'c=d']);
});
it('headerValue should return set-cookie from intercepted response', async ({ page, server, browserName }) => {
it.fail(browserName === 'chromium', 'Set-Cookie is missing in response after interception');
await page.route('**/empty.html', async route => {
route.fulfill({
status: 200,
headers: {
'Set-Cookie': 'a=b',
},
body: ''
});
});
const response = await page.goto(server.EMPTY_PAGE);
expect(await response.headerValue('Set-Cookie')).toBe('a=b');
});