Skip to content

Commit

Permalink
fix(setInputFiles): make it work with CSP enabled (#3756)
Browse files Browse the repository at this point in the history
We used to do fetch() to decode the file buffer. However, this is
blocked by strict CSP policy. Instead, we can use explicit
string -> bytes conversion, and trade performance for CSP compliance.
  • Loading branch information
dgozman authored Sep 3, 2020
1 parent f232f34 commit c190310
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 5 deletions.
10 changes: 5 additions & 5 deletions src/server/injected/injectedScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ export class InjectedScript {
throw new Error('Not a checkbox');
}

async setInputFiles(node: Node, payloads: { name: string, mimeType: string, buffer: string }[]) {
setInputFiles(node: Node, payloads: { name: string, mimeType: string, buffer: string }[]) {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'Node is not of type HTMLElement';
const element: Element | undefined = node as Element;
Expand All @@ -463,10 +463,10 @@ export class InjectedScript {
if (type !== 'file')
return 'Not an input[type=file] element';

const files = await Promise.all(payloads.map(async file => {
const result = await fetch(`data:${file.mimeType};base64,${file.buffer}`);
return new File([await result.blob()], file.name, {type: file.mimeType});
}));
const files = payloads.map(file => {
const bytes = Uint8Array.from(atob(file.buffer), c => c.charCodeAt(0));
return new File([bytes], file.name, { type: file.mimeType });
});
const dt = new DataTransfer();
for (const file of files)
dt.items.add(file);
Expand Down
9 changes: 9 additions & 0 deletions test/page-set-input-files.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ it('should work when file input is not attached to DOM', async ({page, server})
expect(chooser).toBeTruthy();
});

it('should work with CSP', async ({page, server}) => {
server.setCSP('/empty.html', 'default-src "none"');
await page.goto(server.EMPTY_PAGE);
await page.setContent(`<input type=file>`);
await page.setInputFiles('input', path.join(__dirname, '/assets/file-to-upload.txt'));
expect(await page.$eval('input', input => input.files.length)).toBe(1);
expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt');
});

it('should respect timeout', async ({page, playwright}) => {
let error = null;
await page.waitForEvent('filechooser', {timeout: 1}).catch(e => error = e);
Expand Down

0 comments on commit c190310

Please sign in to comment.