fix: route.continue should not change multipart form data body (#30863)

The bug was fixed in https://github.com/microsoft/playwright/pull/30734.
This PR adds a test and updates interception logic to not send post data
when it is not modified.

Fixes https://github.com/microsoft/playwright/issues/30788
This commit is contained in:
Yury Semikhatsky 2024-05-20 16:36:57 -07:00 committed by GitHub
parent b67b9634c1
commit 042896472b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 3 deletions

View File

@ -101,7 +101,6 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
if (this._redirectedFrom) if (this._redirectedFrom)
this._redirectedFrom._redirectedTo = this; this._redirectedFrom._redirectedTo = this;
this._provisionalHeaders = new RawHeaders(initializer.headers); this._provisionalHeaders = new RawHeaders(initializer.headers);
this._fallbackOverrides.postDataBuffer = initializer.postData;
this._timing = { this._timing = {
startTime: 0, startTime: 0,
domainLookupStart: -1, domainLookupStart: -1,
@ -128,11 +127,11 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
} }
postData(): string | null { postData(): string | null {
return this._fallbackOverrides.postDataBuffer?.toString('utf-8') || null; return (this._fallbackOverrides.postDataBuffer || this._initializer.postData)?.toString('utf-8') || null;
} }
postDataBuffer(): Buffer | null { postDataBuffer(): Buffer | null {
return this._fallbackOverrides.postDataBuffer || null; return this._fallbackOverrides.postDataBuffer || this._initializer.postData || null;
} }
postDataJSON(): Object | null { postDataJSON(): Object | null {

View File

@ -477,3 +477,46 @@ it('should intercept css variable with background url', async ({ page, server })
await page.waitForTimeout(1000); await page.waitForTimeout(1000);
expect(interceptedRequests).toBe(1); expect(interceptedRequests).toBe(1);
}); });
it('continue should not change multipart/form-data body', async ({ page, server, browserName }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/19158' });
await page.goto(server.EMPTY_PAGE);
server.setRoute('/upload', (request, response) => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.end('done');
});
async function sendFormData() {
const reqPromise = server.waitForRequest('/upload');
const status = await page.evaluate(async () => {
const newFile = new File(['file content'], 'file.txt');
const formData = new FormData();
formData.append('file', newFile);
const response = await fetch('/upload', {
method: 'POST',
credentials: 'include',
body: formData,
});
return response.status;
});
const req = await reqPromise;
expect(status).toBe(200);
return req;
}
const reqBefore = await sendFormData();
await page.route('**/*', async route => {
await route.continue();
});
const reqAfter = await sendFormData();
const fileContent = [
'Content-Disposition: form-data; name=\"file\"; filename=\"file.txt\"',
'Content-Type: application/octet-stream',
'',
'file content',
'------'].join('\r\n');
expect.soft((await reqBefore.postBody).toString('utf8')).toContain(fileContent);
expect.soft((await reqAfter.postBody).toString('utf8')).toContain(fileContent);
// Firefox sends a bit longer boundary.
const expectedLength = browserName === 'firefox' ? '246' : '208';
expect.soft(reqBefore.headers['content-length']).toBe(expectedLength);
expect.soft(reqAfter.headers['content-length']).toBe(expectedLength);
});