fix(trace-viewer): encode attachment filenames as UTF-8 (#29993)

Fixes https://github.com/microsoft/playwright/issues/29967

Tested in Firefox, Chromium, and Safari. This now leads to "good
attachment names" in Chromium and Safari, for Firefox, it won't produce
attachments, it will open them inline, but this is not a regression, was
before like that already.

See here for the spec:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#filename_2

---------

Signed-off-by: Max Schmitt <max@schmitt.mx>
This commit is contained in:
Max Schmitt 2024-03-18 21:26:45 +01:00 committed by GitHub
parent 35db70ea1d
commit a6d1fb93de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 13 additions and 7 deletions

View File

@ -159,7 +159,7 @@ function downloadHeadersForAttachment(traceModel: TraceModel, sha1: string): Hea
if (!attachment)
return;
const headers = new Headers();
headers.set('Content-Disposition', `attachment; filename="${attachment.name}"`);
headers.set('Content-Disposition', `attachment; filename="attachment"; filename*=UTF-8''${encodeURIComponent(attachment.name)}`);
if (attachment.contentType)
headers.set('Content-Type', attachment.contentType);
return headers;

View File

@ -24,6 +24,7 @@ test('should contain text attachment', async ({ runUITest }) => {
import { test } from '@playwright/test';
test('attach test', async () => {
await test.info().attach('note', { path: __filename });
await test.info().attach('🎭', { body: 'hi tester!', contentType: 'text/plain' });
});
`,
});
@ -31,12 +32,17 @@ test('should contain text attachment', async ({ runUITest }) => {
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
await page.getByText('Attachments').click();
await page.getByText('attach "note"', { exact: true }).click();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: 'note' }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe('note');
expect((await readAllFromStream(await download.createReadStream())).toString()).toContain('attach test');
for (const { name, content } of [
{ name: 'note', content: 'attach test' },
{ name: '🎭', content: 'hi tester!' }
]) {
await page.getByText(`attach "${name}"`, { exact: true }).click();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: name }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(name);
expect((await readAllFromStream(await download.createReadStream())).toString()).toContain(content);
}
});
test('should contain binary attachment', async ({ runUITest }) => {